diff options
Diffstat (limited to 'MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs')
| -rw-r--r-- | MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs | 118 |
1 files changed, 77 insertions, 41 deletions
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs index e752a863d..68e552d3c 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegAudioImageProvider.cs @@ -1,21 +1,23 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Concurrent; +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.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Logging; namespace MediaBrowser.Controller.Providers.MediaInfo { /// <summary> /// Uses ffmpeg to create video images /// </summary> - public class FFMpegAudioImageProvider : BaseFFMpegImageProvider<Audio> + public class FFMpegAudioImageProvider : BaseFFMpegProvider<Audio> { - public FFMpegAudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager) : base(logManager, configurationManager) + public FFMpegAudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager) + : base(logManager, configurationManager) { } @@ -25,67 +27,101 @@ namespace MediaBrowser.Controller.Providers.MediaInfo 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> /// 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) + public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - var audio = (Audio)item; + var success = ProviderRefreshStatus.Success; - if (string.IsNullOrEmpty(audio.PrimaryImagePath)) + if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) { - // First try to use the parent's image - audio.PrimaryImagePath = audio.ResolveArgs.Parent.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 (string.IsNullOrEmpty(audio.PrimaryImagePath)) + if (force || string.IsNullOrEmpty(item.PrimaryImagePath)) { + var audio = (Audio)item; + if (audio.MediaStreams != null && audio.MediaStreams.Any(s => s.Type == MediaStreamType.Video)) { - var filename = item.Id + "_" + item.DateModified.Ticks + "_primary"; + 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, ".jpg"); + var path = Kernel.Instance.FFMpegManager.AudioImageCache.GetResourcePath(filename + "_primary", ".jpg"); if (!Kernel.Instance.FFMpegManager.AudioImageCache.ContainsFilePath(path)) { - return ExtractImage(audio, path, cancellationToken); - } - - // Image is already in the cache - audio.PrimaryImagePath = path; - } + var semaphore = GetLock(path); - } - } + // Acquire a lock + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - SetLastRefreshed(item, DateTime.UtcNow); - return TrueTaskResult; - } + // Check again + if (!Kernel.Instance.FFMpegManager.AudioImageCache.ContainsFilePath(path)) + { + try + { + var imageSucceeded = await Kernel.Instance.FFMpegManager.ExtractAudioImage(audio.Path, path, cancellationToken).ConfigureAwait(false); - /// <summary> - /// Extracts the image. - /// </summary> - /// <param name="audio">The audio.</param> - /// <param name="path">The path.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - private async Task<bool> ExtractImage(Audio audio, string path, CancellationToken cancellationToken) - { - var success = await Kernel.Instance.FFMpegManager.ExtractImage(audio, path, cancellationToken).ConfigureAwait(false); + if (!imageSucceeded) + { + success = ProviderRefreshStatus.Failure; + } + } + finally + { + semaphore.Release(); + } + } + else + { + semaphore.Release(); + } + } - if (success) - { - audio.PrimaryImagePath = path; - SetLastRefreshed(audio, DateTime.UtcNow); - } - else - { - SetLastRefreshed(audio, DateTime.UtcNow, ProviderRefreshStatus.Failure); + if (success == ProviderRefreshStatus.Success) + { + // Image is already in the cache + audio.PrimaryImagePath = path; + } + } + } } + SetLastRefreshed(item, DateTime.UtcNow, success); return true; } } |
