using MediaBrowser.Common.MediaInfo; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.MediaInfo; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Providers.MediaInfo { /// /// Provides a base class for extracting media information through ffprobe /// /// public abstract class BaseFFProbeProvider : BaseMetadataProvider where T : BaseItem, IHasMediaStreams { protected BaseFFProbeProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder, IJsonSerializer jsonSerializer) : base(logManager, configurationManager) { JsonSerializer = jsonSerializer; MediaEncoder = mediaEncoder; } protected readonly IMediaEncoder MediaEncoder; protected readonly IJsonSerializer JsonSerializer; /// /// Gets the priority. /// /// The priority. public override MetadataProviderPriority Priority { get { return MetadataProviderPriority.First; } } protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// /// Supportses the specified item. /// /// The item. /// true if XXXX, false otherwise public override bool Supports(BaseItem item) { return item.LocationType == LocationType.FileSystem && item is T; } /// /// Override this to return the date that should be compared to the last refresh date /// to determine if this provider should be re-fetched. /// /// The item. /// DateTime. protected override DateTime CompareDate(BaseItem item) { return item.DateModified; } /// /// The null mount task result /// protected readonly Task NullMountTaskResult = Task.FromResult(null); /// /// Gets the provider version. /// /// The provider version. protected override string ProviderVersion { get { return "ffmpeg20131209"; } } /// /// Gets a value indicating whether [refresh on version change]. /// /// true if [refresh on version change]; otherwise, false. protected override bool RefreshOnVersionChange { get { return true; } } /// /// Gets the media info. /// /// The item. /// The iso mount. /// The cancellation token. /// Task{MediaInfoResult}. /// inputPath /// or /// cache protected async Task GetMediaInfo(BaseItem item, IIsoMount isoMount, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var type = InputType.AudioFile; var inputPath = isoMount == null ? new[] { item.Path } : new[] { isoMount.MountedPath }; var video = item as Video; if (video != null) { inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type); } return await MediaEncoder.GetMediaInfo(inputPath, type, cancellationToken).ConfigureAwait(false); } /// /// Mounts the iso if needed. /// /// The item. /// The cancellation token. /// IsoMount. protected virtual Task MountIsoIfNeeded(T item, CancellationToken cancellationToken) { return NullMountTaskResult; } /// /// Called when [pre fetch]. /// /// The item. /// The mount. protected virtual void OnPreFetch(T item, IIsoMount mount) { } /// /// Normalizes the FF probe result. /// /// The result. protected void NormalizeFFProbeResult(MediaInfoResult result) { if (result.format != null && result.format.tags != null) { result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags); } if (result.streams != null) { // Convert all dictionaries to case insensitive foreach (var stream in result.streams) { if (stream.tags != null) { stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags); } if (stream.disposition != null) { stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition); } } } } /// /// Gets a string from an FFProbeResult tags dictionary /// /// The tags. /// The key. /// System.String. protected string GetDictionaryValue(Dictionary tags, string key) { if (tags == null) { return null; } string val; tags.TryGetValue(key, out val); return val; } /// /// Gets an int from an FFProbeResult tags dictionary /// /// The tags. /// The key. /// System.Nullable{System.Int32}. protected int? GetDictionaryNumericValue(Dictionary tags, string key) { var val = GetDictionaryValue(tags, key); if (!string.IsNullOrEmpty(val)) { int i; if (int.TryParse(val, out i)) { return i; } } return null; } /// /// Gets a DateTime from an FFProbeResult tags dictionary /// /// The tags. /// The key. /// System.Nullable{DateTime}. protected DateTime? GetDictionaryDateTime(Dictionary tags, string key) { var val = GetDictionaryValue(tags, key); if (!string.IsNullOrEmpty(val)) { DateTime i; if (DateTime.TryParse(val, out i)) { return i.ToUniversalTime(); } } return null; } /// /// Converts a dictionary to case insensitive /// /// The dict. /// Dictionary{System.StringSystem.String}. private Dictionary ConvertDictionaryToCaseInSensitive(Dictionary dict) { return new Dictionary(dict, StringComparer.OrdinalIgnoreCase); } } }