/// <summary>
        /// Initializes a new instance.
        /// </summary>
        private void Initialize()
        {
            Log.Debug("BassMODFileInputSource.Initialize()");

            const BASSFlag flags = BASSFlag.BASS_SAMPLE_SOFTWARE | BASSFlag.BASS_SAMPLE_FLOAT |
                                   BASSFlag.BASS_MUSIC_AUTOFREE | BASSFlag.BASS_MUSIC_PRESCAN;

            int handle;
            ILocalFsResourceAccessor lfra = _accessor as ILocalFsResourceAccessor;

            if (lfra == null)
            { // Build stream reading procs for the resource's input stream
                Stream inputStream = _accessor.OpenRead();
                int    length      = (int)inputStream.Length;
                byte[] audioData   = new byte[length];
                inputStream.Read(audioData, 0, length);
                handle = Bass.BASS_MusicLoad(audioData, 0, length, flags, 0);
            }
            else
            {
                // Optimize access to local filesystem resource
                using (lfra.EnsureLocalFileSystemAccess())
                    handle = Bass.BASS_MusicLoad(lfra.LocalFileSystemPath, 0, 0, flags, 0);
            }

            if (handle == BassConstants.BassInvalidHandle)
            {
                throw new BassLibraryException("BASS_MusicLoad");
            }

            _bassStream = BassStream.Create(handle);
        }
        /// <summary>
        /// Creates an <see cref="IInputSource"/> object for a given mediaitem.
        /// </summary>
        /// <param name="resourceLocator">Locator instance to the media item to create the input source for.</param>
        /// <param name="mimeType">Mime type of the media item, if present. May be <c>null</c>.</param>
        /// <returns>Input source object for the given <paramref name="resourceLocator"/> or <c>null</c>, if no input source
        /// could be created.</returns>
        public IInputSource CreateInputSource(IResourceLocator resourceLocator, string mimeType)
        {
            if (!CanPlay(resourceLocator, mimeType))
            {
                return(null);
            }
            IInputSource result;

            _accessor = resourceLocator.CreateAccessor();

            AudioCDResourceAccessor acdra = _accessor as AudioCDResourceAccessor;

            if (acdra != null)
            {
                result = BassCDTrackInputSource.Create(acdra.Drive, acdra.TrackNo);
            }
            else
            {
                string filePath = _accessor.ResourcePathName;
                // Network streams
                INetworkResourceAccessor netra = _accessor as INetworkResourceAccessor;
                if (netra != null)
                {
                    result = BassWebStreamInputSource.Create(netra.URL);
                }
                // CDDA
                else if (URLUtils.IsCDDA(filePath))
                {
                    ILocalFsResourceAccessor lfra = _accessor as ILocalFsResourceAccessor;
                    if (lfra == null)
                    {
                        return(null);
                    }
                    using (lfra.EnsureLocalFileSystemAccess())
                        result = BassFsCDTrackInputSource.Create(lfra.LocalFileSystemPath);
                }
                else
                {
                    // Filesystem resources
                    IFileSystemResourceAccessor fsra = _accessor as IFileSystemResourceAccessor;
                    if (fsra == null)
                    {
                        return(null);
                    }
                    if (URLUtils.IsMODFile(filePath))
                    {
                        result = BassMODFileInputSource.Create(fsra);
                    }
                    else
                    {
                        result = BassAudioFileInputSource.Create(fsra);
                    }
                }
            }
            Log.Debug("InputSourceFactory: Creating input source for media resource '{0}' of type '{1}'", _accessor, result.GetType());
            return(result);
        }
예제 #3
0
        private bool CollectionFolderHasFanArt(ILocalFsResourceAccessor lfsra, out string collectionName)
        {
            collectionName = null;

            // File based access
            try
            {
                using (lfsra.EnsureLocalFileSystemAccess())
                {
                    string collectionMediaItemDirectoryPath;
                    if (Directory.GetParent(lfsra.LocalFileSystemPath) != null && Directory.GetParent(Directory.GetParent(lfsra.LocalFileSystemPath).FullName) != null)
                    {
                        DirectoryInfo dir = Directory.GetParent(Directory.GetParent(lfsra.LocalFileSystemPath).FullName);
                        collectionMediaItemDirectoryPath = dir.FullName;
                        collectionName = dir.Name;
                    }
                    else
                    {
                        return(false);
                    }

                    var potentialFanArtFiles = GetPotentialFanArtFiles(collectionMediaItemDirectoryPath);

                    if ((from potentialFanArtFile in potentialFanArtFiles
                         let potentialFanArtFileNameWithoutExtension = Path.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant()
                                                                       where potentialFanArtFileNameWithoutExtension == "poster" || potentialFanArtFileNameWithoutExtension == "folder" || potentialFanArtFileNameWithoutExtension == "keyart" ||
                                                                       potentialFanArtFileNameWithoutExtension.StartsWith("backdrop") || potentialFanArtFileNameWithoutExtension.StartsWith("fanart") ||
                                                                       potentialFanArtFileNameWithoutExtension == "banner" ||
                                                                       potentialFanArtFileNameWithoutExtension.StartsWith("movieset-")
                                                                       select potentialFanArtFile).Count() > 0)
                    {
                        return(true);
                    }

                    string fanArtFolder = Path.Combine(collectionMediaItemDirectoryPath, "ExtraFanArt");
                    if (Directory.Exists(fanArtFolder))
                    {
                        if (GetPotentialFanArtFiles(fanArtFolder).Count() > 0)
                        {
                            return(true);
                        }
                    }
                }
            }
            catch
            {
            }
            return(false);
        }
        protected void ExtractThumbnailData(ILocalFsResourceAccessor lfsra, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            // In quick mode only allow thumbs taken from cache.
            bool cachedOnly = forceQuickMode;

            // Thumbnail extraction
            IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();

            byte[]    thumbData;
            ImageType imageType;

            using (lfsra.EnsureLocalFileSystemAccess())
                if (generator.GetThumbnail(lfsra.LocalFileSystemPath, 256, 256, cachedOnly, out thumbData, out imageType))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                }
        }
예제 #5
0
        public static bool ExtractFromTags(ILocalFsResourceAccessor folderOrFileLfsra, MovieInfo movieInfo)
        {
            // Calling EnsureLocalFileSystemAccess not necessary; only string operation
            string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToUpper();

            // Try to get extended information out of MP4 files)
            if (extensionUpper != ".MP4")
            {
                return(false);
            }

            using (folderOrFileLfsra.EnsureLocalFileSystemAccess())
            {
                TagLib.File mp4File = TagLib.File.Create(folderOrFileLfsra.LocalFileSystemPath);
                if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null))
                {
                    return(false);
                }

                TagLib.Tag tag = mp4File.Tag;

                if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0)
                {
                    List <GenreInfo> genreList = tag.Genres.Select(s => new GenreInfo {
                        Name = s
                    }).ToList();
                    OnlineMatcherService.Instance.AssignMissingMovieGenreIds(genreList);
                    movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Genres, genreList, movieInfo.Genres.Count == 0);
                }

                if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0)
                {
                    movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Actors,
                                                                            tag.Performers.Select(t => new PersonInfo()
                    {
                        Name = t, Occupation = PersonAspect.OCCUPATION_ACTOR, MediaName = movieInfo.MovieName.Text
                    }).ToList(), false);
                }

                //Clean up memory
                mp4File.Dispose();

                return(true);
            }
        }
        protected void ExtractMp4Tags(ILocalFsResourceAccessor lfsra, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            // Calling EnsureLocalFileSystemAccess not necessary; only string operation
            string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(lfsra.LocalFileSystemPath)).ToUpper();

            // Try to get extended information out of MP4 files)
            if (extensionUpper != ".MP4")
            {
                return;
            }

            using (lfsra.EnsureLocalFileSystemAccess())
            {
                TagLib.File mp4File = TagLib.File.Create(lfsra.LocalFileSystemPath);
                if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null))
                {
                    return;
                }

                TagLib.Tag tag = mp4File.Tag;

                string title = tag.Title;
                if (!string.IsNullOrEmpty(title))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                }

                int year = (int)tag.Year;
                if (year != 0)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));
                }

                if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0)
                {
                    MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_GENRES, tag.Genres);
                }

                if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0)
                {
                    MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_ACTORS, tag.Performers);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Tries to create a LocalResourceAccessor for the given <paramref name="metaFilePath"/> and to read the contents to match the IMDB id.
        /// </summary>
        /// <param name="metaFilePath">Path to file</param>
        /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param>
        /// <returns>true if matched</returns>
        private static bool TryRead(string metaFilePath, out string imdbId)
        {
            imdbId = null;
            IResourceAccessor metaFileAccessor;

            if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out metaFileAccessor))
            {
                return(false);
            }

            using (metaFileAccessor)
            {
                ILocalFsResourceAccessor lfsra = metaFileAccessor as ILocalFsResourceAccessor;
                if (lfsra == null || !lfsra.Exists)
                {
                    return(false);
                }
                string content;
                using (lfsra.EnsureLocalFileSystemAccess())
                    content = File.ReadAllText(lfsra.LocalFileSystemPath);
                return(ImdbIdMatcher.TryMatchImdbId(content, out imdbId));
            }
        }
예제 #8
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);
        }
    protected void ExtractThumbnailData(ILocalFsResourceAccessor lfsra, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      // In quick mode only allow thumbs taken from cache.
      bool cachedOnly = forceQuickMode;

      // Thumbnail extraction
      IThumbnailGenerator generator = ServiceRegistration.Get<IThumbnailGenerator>();
      byte[] thumbData;
      ImageType imageType;
      using (lfsra.EnsureLocalFileSystemAccess())
        if (generator.GetThumbnail(lfsra.LocalFileSystemPath, 256, 256, cachedOnly, out thumbData, out imageType))
          MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
    }
예제 #10
0
    protected void ExtractMp4Tags(ILocalFsResourceAccessor lfsra, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      // Calling EnsureLocalFileSystemAccess not necessary; only string operation
      string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(lfsra.LocalFileSystemPath)).ToUpper();

      // Try to get extended information out of MP4 files)
      if (extensionUpper != ".MP4") return;

      using (lfsra.EnsureLocalFileSystemAccess())
      {
        TagLib.File mp4File = TagLib.File.Create(lfsra.LocalFileSystemPath);
        if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null))
          return;

        TagLib.Tag tag = mp4File.Tag;

        string title = tag.Title;
        if (!string.IsNullOrEmpty(title))
          MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);

        int year = (int)tag.Year;
        if (year != 0)
          MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));

        if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0)
          MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_GENRES, tag.Genres);

        if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0)
          MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_ACTORS, tag.Performers);
      }
    }
        private Task <bool> ExtractThumbnailAsync(ILocalFsResourceAccessor lfsra, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData)
        {
            // We can only work on files and make sure this file was detected by a lower MDE before (title is set then).
            // VideoAspect must be present to be sure it is actually a video resource.
            if (!lfsra.IsFile || !extractedAspectData.ContainsKey(VideoStreamAspect.ASPECT_ID))
            {
                return(Task.FromResult(false));
            }

            //ServiceRegistration.Get<ILogger>().Info("OCVVideoThumbnailer: Evaluate {0}", lfsra.ResourceName);

            bool isPrimaryResource = false;
            IList <MultipleMediaItemAspect> resourceAspects;

            if (MediaItemAspect.TryGetAspects(extractedAspectData, ProviderResourceAspect.Metadata, out resourceAspects))
            {
                foreach (MultipleMediaItemAspect pra in resourceAspects)
                {
                    string       accessorPath = (string)pra.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                    ResourcePath resourcePath = ResourcePath.Deserialize(accessorPath);
                    if (resourcePath.Equals(lfsra.CanonicalLocalResourcePath))
                    {
                        if (pra.GetAttributeValue <int?>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY)
                        {
                            isPrimaryResource = true;
                            break;
                        }
                    }
                }
            }

            if (!isPrimaryResource) //Ignore subtitles
            {
                return(Task.FromResult(false));
            }

            // Check for a reasonable time offset
            int    defaultVideoOffset = 720;
            long   videoDuration;
            double downscale = 2; // Reduces the video frame size to a half of original
            IList <MultipleMediaItemAspect> videoAspects;

            if (MediaItemAspect.TryGetAspects(extractedAspectData, VideoStreamAspect.Metadata, out videoAspects))
            {
                if ((videoDuration = videoAspects[0].GetAttributeValue <long>(VideoStreamAspect.ATTR_DURATION)) > 0)
                {
                    if (defaultVideoOffset > videoDuration * 1 / 3)
                    {
                        defaultVideoOffset = Convert.ToInt32(videoDuration * 1 / 3);
                    }
                }

                double width  = videoAspects[0].GetAttributeValue <int>(VideoStreamAspect.ATTR_WIDTH);
                double height = videoAspects[0].GetAttributeValue <int>(VideoStreamAspect.ATTR_HEIGHT);
                downscale = width / 256.0; //256 is max size of large thumbnail aspect
            }

            using (lfsra.EnsureLocalFileSystemAccess())
            {
                using (VideoCapture capture = new VideoCapture())
                {
                    capture.Open(lfsra.LocalFileSystemPath);
                    capture.PosMsec = defaultVideoOffset * 1000;
                    using (var mat = capture.RetrieveMat())
                    {
                        if (mat.Height > 0 && mat.Width > 0)
                        {
                            double width  = mat.Width;
                            double height = mat.Height;
                            ServiceRegistration.Get <ILogger>().Debug("OCVVideoThumbnailer: Scaling thumbnail of size {1}x{2} for resource '{0}'", lfsra.LocalFileSystemPath, width, height);
                            using (var scaledMat = mat.Resize(new OpenCvSharp.Size(width / downscale, height / downscale)))
                            {
                                var binary = scaledMat.ToBytes();
                                MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, binary);
                                ServiceRegistration.Get <ILogger>().Info("OCVVideoThumbnailer: Successfully created thumbnail for resource '{0}'", lfsra.LocalFileSystemPath);
                            }
                        }
                        else
                        {
                            ServiceRegistration.Get <ILogger>().Warn("OCVVideoThumbnailer: Failed to create thumbnail for resource '{0}'", lfsra.LocalFileSystemPath);
                        }
                    }
                }
            }
            return(Task.FromResult(true));
        }
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            try
            {
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }

                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                {
                    ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor;
                    if (!lfsra.IsFile && lfsra.ResourceExists("BDMV"))
                    {
                        IFileSystemResourceAccessor fsraBDMV = lfsra.GetResource("BDMV");
                        if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv"))
                        {
                            // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video!
                            MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
                            MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);

                            mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc

                            using (lfsra.EnsureLocalFileSystemAccess())
                            {
                                BDInfoExt bdinfo = new BDInfoExt(lfsra.LocalFileSystemPath);
                                string    title  = bdinfo.GetTitle();
                                mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title ?? mediaItemAccessor.ResourceName);

                                // Check for BD disc thumbs
                                FileInfo thumbnail = bdinfo.GetBiggestThumb();
                                if (thumbnail != null)
                                {
                                    try
                                    {
                                        using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read))
                                            using (MemoryStream resized = (MemoryStream)ImageUtilities.ResizeImage(fileStream, 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
                                    {
                                    }
                                }
                            }
                            return(true);
                        }
                    }
                }
                return(false);
            }
            catch
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                if (mediaItemAccessor != null)
                {
                    ServiceRegistration.Get <ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName);
                }
                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);
        }
예제 #14
0
        private void ReadFile(params ElementDescriptor[] elements)
        {
            IEnumerable <ElementDescriptor> wantedElements = elements;

            if (wantedElements.Count() > 0 && wantedElements.All(e => _elementsRead.Contains(e.Identifier.EncodedValue)))
            {
                return;
            }

            SortedSet <long> wantedElementPositions = new SortedSet <long>();

            using (_lfsra.EnsureLocalFileSystemAccess())
                using (var fs = new FileStream(_lfsra.LocalFileSystemPath, FileMode.Open, FileAccess.Read))
                    using (EbmlReader ebmlReader = new EbmlReader(fs))
                    {
                        if (fs.Length == 0)
                        {
                            return;
                        }

                        try
                        {
                            while (ebmlReader.ReadNext())
                            {
                                //Segment element contains all the data we need
                                if (ebmlReader.ElementId == SegmentElement.Identifier)
                                {
                                    ebmlReader.EnterContainer();
                                    while (ebmlReader.ReadNext())
                                    {
                                        //Find file position of relevant elements via seek heads
                                        if (ebmlReader.ElementId == SeekHeadElement.Identifier)
                                        {
                                            long elementOffset = ebmlReader.ElementPosition;
                                            var  seekElements  = ReadSeekHeads(ebmlReader);
                                            if (seekElements?.Count > 0)
                                            {
                                                //Find all the wanted or possible elements
                                                var availableSegments = seekElements.Select(a => a.Element);
                                                var newElements       = wantedElements.Count() > 0 ? wantedElements.Intersect(availableSegments) : availableSegments.AsEnumerable();
                                                if (newElements != null)
                                                {
                                                    wantedElements = newElements;
                                                }

                                                //Find file positions of wanted elements
                                                foreach (var e in seekElements.Where(e => wantedElements.Any(n => n.Identifier == e.Element.Identifier)))
                                                {
                                                    wantedElementPositions.Add(Convert.ToInt64(e.Position) + elementOffset);
                                                }
                                            }
                                        }
                                        else if (ShouldReadElement(ebmlReader.ElementId, wantedElements.ToArray()))
                                        {
                                            //Read wanted elements
                                            if (ebmlReader.ElementId == SegmentInfoElement.Identifier)
                                            {
                                                ReadInfo(ebmlReader);
                                            }
                                            else if (ebmlReader.ElementId == TagsElement.Identifier)
                                            {
                                                ReadTags(ebmlReader);
                                            }
                                            else if (ebmlReader.ElementId == TracksElement.Identifier)
                                            {
                                                ReadTracks(ebmlReader);
                                            }
                                            else if (ebmlReader.ElementId == AttachmentsElement.Identifier)
                                            {
                                                ReadAttachments(ebmlReader);
                                            }

                                            _elementsRead.Add(ebmlReader.ElementId.EncodedValue);
                                        }

                                        //All wanted elements read so exit
                                        if (wantedElements.Count() == 0 || wantedElements.All(e => _elementsRead.Contains(e.Identifier.EncodedValue)))
                                        {
                                            return;
                                        }

                                        //Skip to next position in file if possible
                                        wantedElementPositions.RemoveWhere(p => p < (fs.Position));
                                        if (fs.Position < wantedElementPositions.FirstOrDefault())
                                        {
                                            fs.Position = wantedElementPositions.First();
                                        }

                                        //Exit if we reading past the file length
                                        if ((fs.Position + ebmlReader.ElementSize) >= fs.Length)
                                        {
                                            return;
                                        }
                                    }
                                    ebmlReader.LeaveContainer();
                                    break;
                                }
                                //Exit if we reading past the file length
                                if ((fs.Position + ebmlReader.ElementSize) >= fs.Length)
                                {
                                    break;
                                }
                            }
                        }
                        catch (EbmlDataFormatException)
                        {
                            //Rest of the EBML seems to be invalid so ignore it
                            ServiceRegistration.Get <ILogger>().Warn("MatroskaInfoReader: Matroska file '{0}' has invalid EBML elements", _lfsra.LocalFileSystemPath);
                        }
                    }
        }