diff options
Diffstat (limited to 'MediaBrowser.Controller/Providers')
3 files changed, 101 insertions, 331 deletions
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs new file mode 100644 index 000000000..05e4ba1e3 --- /dev/null +++ b/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs @@ -0,0 +1,101 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Providers.MediaInfo +{ + /// <summary> + /// Uses ffmpeg to create video images + /// </summary> + public class AudioImageProvider : BaseMetadataProvider + { + /// <summary> + /// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class. + /// </summary> + /// <param name="logManager">The log manager.</param> + /// <param name="configurationManager">The configuration manager.</param> + public AudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager) + : base(logManager, configurationManager) + { + } + + /// <summary> + /// The true task result + /// </summary> + protected static readonly Task<bool> TrueTaskResult = Task.FromResult(true); + + /// <summary> + /// Supportses the specified item. + /// </summary> + /// <param name="item">The item.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + public override bool Supports(BaseItem item) + { + return item.LocationType == LocationType.FileSystem && item is Audio; + } + + /// <summary> + /// Override this to return the date that should be compared to the last refresh date + /// to determine if this provider should be re-fetched. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>DateTime.</returns> + protected override DateTime CompareDate(BaseItem item) + { + return item.DateModified; + } + + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Last; } + } + + /// <summary> + /// Needses the refresh internal. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="providerInfo">The provider info.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + { + if (!string.IsNullOrEmpty(item.PrimaryImagePath)) + { + return false; + } + return base.NeedsRefreshInternal(item, providerInfo); + } + + /// <summary> + /// Fetches metadata and returns true or false indicating if any work that requires persistence was done + /// </summary> + /// <param name="item">The item.</param> + /// <param name="force">if set to <c>true</c> [force].</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{System.Boolean}.</returns> + public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) + { + if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) + { + var album = item.ResolveArgs.Parent as MusicAlbum; + + if (album != null) + { + // First try to use the parent's image + item.PrimaryImagePath = item.ResolveArgs.Parent.PrimaryImagePath; + } + } + + SetLastRefreshed(item, DateTime.UtcNow); + return TrueTaskResult; + } + } +} diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs deleted file mode 100644 index e1cbc6932..000000000 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs +++ /dev/null @@ -1,143 +0,0 @@ -using MediaBrowser.Common.MediaInfo; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Providers.MediaInfo -{ - /// <summary> - /// Uses ffmpeg to create video images - /// </summary> - public class FFMpegAudioImageProvider : BaseFFMpegProvider<Audio> - { - public FFMpegAudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder) - : base(logManager, configurationManager, mediaEncoder) - { - } - - /// <summary> - /// The true task result - /// </summary> - protected static readonly Task<bool> TrueTaskResult = Task.FromResult(true); - - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.Last; } - } - - /// <summary> - /// The _locks - /// </summary> - private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>(); - - /// <summary> - /// Gets the lock. - /// </summary> - /// <param name="filename">The filename.</param> - /// <returns>System.Object.</returns> - private SemaphoreSlim GetLock(string filename) - { - return _locks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); - } - - /// <summary> - /// Needses the refresh internal. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="providerInfo">The provider info.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) - { - if (!string.IsNullOrEmpty(item.PrimaryImagePath)) - { - return false; - } - return base.NeedsRefreshInternal(item, providerInfo); - } - - /// <summary> - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// </summary> - /// <param name="item">The item.</param> - /// <param name="force">if set to <c>true</c> [force].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) - { - var success = ProviderRefreshStatus.Success; - - if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) - { - var album = item.ResolveArgs.Parent as MusicAlbum; - - if (album != null) - { - // First try to use the parent's image - item.PrimaryImagePath = item.ResolveArgs.Parent.PrimaryImagePath; - } - - // If it's still empty see if there's an embedded image - if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) - { - var audio = (Audio)item; - - if (audio.MediaStreams != null && audio.MediaStreams.Any(s => s.Type == MediaStreamType.Video)) - { - var filename = album != null && string.IsNullOrEmpty(audio.Album + album.DateModified.Ticks) ? (audio.Id.ToString() + audio.DateModified.Ticks) : audio.Album; - - var path = Kernel.Instance.FFMpegManager.AudioImageCache.GetResourcePath(filename + "_primary", ".jpg"); - - if (!Kernel.Instance.FFMpegManager.AudioImageCache.ContainsFilePath(path)) - { - var semaphore = GetLock(path); - - // Acquire a lock - await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - // Check again - if (!Kernel.Instance.FFMpegManager.AudioImageCache.ContainsFilePath(path)) - { - try - { - await MediaEncoder.ExtractImage(new[] { audio.Path }, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false); - } - catch - { - success = ProviderRefreshStatus.Failure; - } - finally - { - semaphore.Release(); - } - } - else - { - semaphore.Release(); - } - } - - if (success == ProviderRefreshStatus.Success) - { - // Image is already in the cache - audio.PrimaryImagePath = path; - } - } - } - } - - SetLastRefreshed(item, DateTime.UtcNow, success); - return true; - } - } -} diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs deleted file mode 100644 index dff4a4ea1..000000000 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs +++ /dev/null @@ -1,188 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Common.MediaInfo; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Providers.MediaInfo -{ - /// <summary> - /// Uses ffmpeg to create video images - /// </summary> - public class FfMpegVideoImageProvider : BaseFFMpegProvider<Video> - { - /// <summary> - /// The _iso manager - /// </summary> - private readonly IIsoManager _isoManager; - - /// <summary> - /// Initializes a new instance of the <see cref="FfMpegVideoImageProvider" /> class. - /// </summary> - /// <param name="isoManager">The iso manager.</param> - /// <param name="logManager">The log manager.</param> - /// <param name="configurationManager">The configuration manager.</param> - /// <param name="mediaEncoder">The media encoder.</param> - public FfMpegVideoImageProvider(IIsoManager isoManager, ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder) - : base(logManager, configurationManager, mediaEncoder) - { - _isoManager = isoManager; - } - - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.Last; } - } - - /// <summary> - /// Supportses the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - public override bool Supports(BaseItem item) - { - if (item.LocationType != LocationType.FileSystem) - { - return false; - } - - var video = item as Video; - - if (video != null) - { - if (video.VideoType == VideoType.Iso && _isoManager.CanMount(item.Path)) - { - return true; - } - - // We can only extract images from folder rips if we know the largest stream path - return video.VideoType == VideoType.VideoFile || video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd; - } - - return false; - } - - /// <summary> - /// Needses the refresh internal. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="providerInfo">The provider info.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) - { - if (!string.IsNullOrEmpty(item.PrimaryImagePath)) - { - return false; - } - return base.NeedsRefreshInternal(item, providerInfo); - } - - /// <summary> - /// The true task result - /// </summary> - protected static readonly Task<bool> TrueTaskResult = Task.FromResult(true); - - /// <summary> - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// </summary> - /// <param name="item">The item.</param> - /// <param name="force">if set to <c>true</c> [force].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) - { - if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) - { - var video = (Video)item; - - // We can only extract images from videos if we know there's an embedded video stream - if (video.MediaStreams != null && video.MediaStreams.Any(m => m.Type == MediaStreamType.Video)) - { - var filename = item.Id + "_" + item.DateModified.Ticks + "_primary"; - - var path = Kernel.Instance.FFMpegManager.VideoImageCache.GetResourcePath(filename, ".jpg"); - - if (!Kernel.Instance.FFMpegManager.VideoImageCache.ContainsFilePath(path)) - { - return ExtractImage(video, path, cancellationToken); - } - - // Image is already in the cache - item.PrimaryImagePath = path; - } - } - - SetLastRefreshed(item, DateTime.UtcNow); - return TrueTaskResult; - } - - /// <summary> - /// Mounts the iso if needed. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>IsoMount.</returns> - protected Task<IIsoMount> MountIsoIfNeeded(Video item, CancellationToken cancellationToken) - { - if (item.VideoType == VideoType.Iso) - { - return _isoManager.Mount(item.Path, cancellationToken); - } - - return NullMountTaskResult; - } - - /// <summary> - /// Extracts the image. - /// </summary> - /// <param name="video">The video.</param> - /// <param name="path">The path.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - private async Task<bool> ExtractImage(Video video, string path, CancellationToken cancellationToken) - { - var isoMount = await MountIsoIfNeeded(video, cancellationToken).ConfigureAwait(false); - - try - { - // If we know the duration, grab it from 10% into the video. Otherwise just 10 seconds in. - // Always use 10 seconds for dvd because our duration could be out of whack - var imageOffset = video.VideoType != VideoType.Dvd && video.RunTimeTicks.HasValue && - video.RunTimeTicks.Value > 0 - ? TimeSpan.FromTicks(Convert.ToInt64(video.RunTimeTicks.Value * .1)) - : TimeSpan.FromSeconds(10); - - InputType type; - - var inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type); - - await MediaEncoder.ExtractImage(inputPath, type, imageOffset, path, cancellationToken).ConfigureAwait(false); - - video.PrimaryImagePath = path; - SetLastRefreshed(video, DateTime.UtcNow); - } - catch - { - SetLastRefreshed(video, DateTime.UtcNow, ProviderRefreshStatus.Failure); - } - finally - { - if (isoMount != null) - { - isoMount.Dispose(); - } - } - - return true; - } - } -} |
