aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/MediaInfo
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/MediaInfo')
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs87
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs94
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs86
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs197
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs13
-rw-r--r--MediaBrowser.Providers/MediaInfo/whitelist.txt1
6 files changed, 365 insertions, 113 deletions
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 20ce952db..772f60163 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -1,5 +1,6 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.MediaInfo;
@@ -7,7 +8,10 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -18,15 +22,19 @@ namespace MediaBrowser.Providers.MediaInfo
/// </summary>
public class AudioImageProvider : IDynamicImageProvider, IHasChangeMonitor
{
+ private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>();
+
private readonly IIsoManager _isoManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
- public AudioImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config)
+ public AudioImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, IFileSystem fileSystem)
{
_isoManager = isoManager;
_mediaEncoder = mediaEncoder;
_config = config;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -65,21 +73,82 @@ namespace MediaBrowser.Providers.MediaInfo
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
- return GetVideoImage((Audio)item, cancellationToken);
+ return GetImage((Audio)item, cancellationToken);
}
- public async Task<DynamicImageResponse> GetVideoImage(Audio item, CancellationToken cancellationToken)
+ public async Task<DynamicImageResponse> GetImage(Audio item, CancellationToken cancellationToken)
{
- var stream = await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.File, true, null, null, cancellationToken).ConfigureAwait(false);
+ var path = GetAudioImagePath(item);
+
+ if (!File.Exists(path))
+ {
+ var semaphore = GetLock(path);
+
+ // Acquire a lock
+ await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ // Check again in case it was saved while waiting for the lock
+ if (!File.Exists(path))
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ using (var stream = await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.File, true, null, null, cancellationToken).ConfigureAwait(false))
+ {
+ using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
+ {
+ await stream.CopyToAsync(fileStream).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ }
return new DynamicImageResponse
{
- Format = ImageFormat.Jpg,
HasImage = true,
- Stream = stream
+ Path = path
};
}
+ private string GetAudioImagePath(Audio item)
+ {
+ var album = item.Parent as MusicAlbum;
+
+ var filename = item.Album ?? string.Empty;
+ filename += item.Artists.FirstOrDefault() ?? string.Empty;
+ filename += album == null ? item.Id.ToString("N") + "_primary" + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks + "_primary";
+
+ filename = filename.GetMD5() + ".jpg";
+
+ var prefix = filename.Substring(0, 1);
+
+ return Path.Combine(AudioImagesPath, prefix, filename);
+ }
+
+ public string AudioImagesPath
+ {
+ get
+ {
+ return Path.Combine(_config.ApplicationPaths.CachePath, "extracted-audio-images");
+ }
+ }
+
+ /// <summary>
+ /// Gets the lock.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns>SemaphoreSlim.</returns>
+ private SemaphoreSlim GetLock(string filename)
+ {
+ return _locks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+ }
+
public string Name
{
get { return "Embedded Image"; }
@@ -90,7 +159,7 @@ namespace MediaBrowser.Providers.MediaInfo
return item.LocationType == LocationType.FileSystem && item is Audio;
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
return item.DateModified > date;
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index 4fc92ddeb..ebb2f13d1 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -1,13 +1,16 @@
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaInfo;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -18,13 +21,17 @@ namespace MediaBrowser.Providers.MediaInfo
{
private readonly IMediaEncoder _mediaEncoder;
private readonly IItemRepository _itemRepo;
+ private readonly IApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public FFProbeAudioInfo(IMediaEncoder mediaEncoder, IItemRepository itemRepo)
+
+ public FFProbeAudioInfo(IMediaEncoder mediaEncoder, IItemRepository itemRepo, IApplicationPaths appPaths, IJsonSerializer json)
{
_mediaEncoder = mediaEncoder;
_itemRepo = itemRepo;
+ _appPaths = appPaths;
+ _json = json;
}
public async Task<ItemUpdateType> Probe<T>(T item, CancellationToken cancellationToken)
@@ -47,10 +54,30 @@ namespace MediaBrowser.Providers.MediaInfo
{
cancellationToken.ThrowIfCancellationRequested();
+ var idString = item.Id.ToString("N");
+ var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-audio", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+
+ try
+ {
+ return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ }
+ catch (FileNotFoundException)
+ {
+
+ }
+ catch (DirectoryNotFoundException)
+ {
+ }
+
const InputType type = InputType.File;
var inputPath = new[] { item.Path };
- return await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+ var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
+ _json.SerializeToFile(result, cachePath);
+
+ return result;
}
/// <summary>
@@ -178,9 +205,14 @@ namespace MediaBrowser.Providers.MediaInfo
FetchStudios(audio, tags, "ensemble");
FetchStudios(audio, tags, "publisher");
}
+
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzArtist, FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"));
}
- private readonly char[] _nameDelimiters = new[] { '/', '|', ';', '\\' };
+ private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
/// <summary>
/// Splits the specified val.
@@ -205,13 +237,63 @@ namespace MediaBrowser.Providers.MediaInfo
val = val.Replace(" featuring ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase)
.Replace(" feat. ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase);
+ var artistsFound = new List<string>();
+
+ foreach (var whitelistArtist in GetSplitWhitelist())
+ {
+ var originalVal = val;
+ val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase);
+
+ if (!string.Equals(originalVal, val, StringComparison.OrdinalIgnoreCase))
+ {
+ // TODO: Preserve casing from original value
+ artistsFound.Add(whitelistArtist);
+ }
+ }
+
// Only use the comma as a delimeter if there are no slashes or pipes.
// We want to be careful not to split names that have commas in them
var delimeter = _nameDelimiters;
- return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
+ var artists = val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
.Where(i => !string.IsNullOrWhiteSpace(i))
.Select(i => i.Trim());
+
+ artistsFound.AddRange(artists);
+ return artistsFound;
+ }
+
+
+ private List<string> _splitWhiteList = null;
+
+ private IEnumerable<string> GetSplitWhitelist()
+ {
+ if (_splitWhiteList == null)
+ {
+ var file = GetType().Namespace + ".whitelist.txt";
+
+ using (var stream = GetType().Assembly.GetManifestResourceStream(file))
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var list = new List<string>();
+
+ while (!reader.EndOfStream)
+ {
+ var val = reader.ReadLine();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ list.Add(val);
+ }
+ }
+
+ _splitWhiteList = list;
+ }
+ }
+ }
+
+ return _splitWhiteList;
}
/// <summary>
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index d55a42d11..7ac48655a 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -12,9 +13,11 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
using System;
using System.Threading;
using System.Threading.Tasks;
+using System.Linq;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -27,7 +30,8 @@ namespace MediaBrowser.Providers.MediaInfo
ICustomMetadataProvider<Trailer>,
ICustomMetadataProvider<Video>,
ICustomMetadataProvider<Audio>,
- IHasChangeMonitor
+ IHasChangeMonitor,
+ IHasOrder
{
private readonly ILogger _logger;
private readonly IIsoManager _isoManager;
@@ -35,58 +39,60 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IItemRepository _itemRepo;
private readonly IBlurayExaminer _blurayExaminer;
private readonly ILocalizationManager _localization;
+ private readonly IApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
public string Name
{
get { return "ffprobe"; }
}
- public Task<ItemUpdateType> FetchAsync(Episode item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(Episode item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(MusicVideo item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(MusicVideo item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(Movie item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(Movie item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(AdultVideo item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(AdultVideo item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(LiveTvVideoRecording item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(LiveTvVideoRecording item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(Trailer item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(Trailer item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(Video item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(Video item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
- return FetchVideoInfo(item, cancellationToken);
+ return FetchVideoInfo(item, directoryService, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(Audio item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(Audio item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
return FetchAudioInfo(item, cancellationToken);
}
- public Task<ItemUpdateType> FetchAsync(LiveTvAudioRecording item, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> FetchAsync(LiveTvAudioRecording item, IDirectoryService directoryService, CancellationToken cancellationToken)
{
return FetchAudioInfo(item, cancellationToken);
}
- public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization)
+ public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json)
{
_logger = logger;
_isoManager = isoManager;
@@ -94,10 +100,12 @@ namespace MediaBrowser.Providers.MediaInfo
_itemRepo = itemRepo;
_blurayExaminer = blurayExaminer;
_localization = localization;
+ _appPaths = appPaths;
+ _json = json;
}
- private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.Unspecified);
- public Task<ItemUpdateType> FetchVideoInfo<T>(T item, CancellationToken cancellationToken)
+ private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
+ public Task<ItemUpdateType> FetchVideoInfo<T>(T item, IDirectoryService directoryService, CancellationToken cancellationToken)
where T : Video
{
if (item.LocationType != LocationType.FileSystem)
@@ -115,9 +123,9 @@ namespace MediaBrowser.Providers.MediaInfo
return _cachedTask;
}
- var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization);
+ var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json);
- return prober.ProbeVideo(item, cancellationToken);
+ return prober.ProbeVideo(item, directoryService, cancellationToken);
}
public Task<ItemUpdateType> FetchAudioInfo<T>(T item, CancellationToken cancellationToken)
@@ -128,14 +136,40 @@ namespace MediaBrowser.Providers.MediaInfo
return _cachedTask;
}
- var prober = new FFProbeAudioInfo(_mediaEncoder, _itemRepo);
+ var prober = new FFProbeAudioInfo(_mediaEncoder, _itemRepo, _appPaths, _json);
return prober.Probe(item, cancellationToken);
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
- return item.DateModified > date;
+ if (item.DateModified > date)
+ {
+ return true;
+ }
+
+ if (item.SupportsLocalMetadata)
+ {
+ var video = item as Video;
+
+ if (video != null)
+ {
+ var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json);
+
+ return !video.SubtitleFiles.SequenceEqual(prober.GetSubtitleFiles(video, directoryService).Select(i => i.FullName).OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ return false;
+ }
+
+ public int Order
+ {
+ get
+ {
+ // Run last
+ return 100;
+ }
}
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 9073441e4..074bcfdff 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -1,13 +1,16 @@
using DvdLib.Ifo;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.MediaInfo;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -26,10 +29,12 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IItemRepository _itemRepo;
private readonly IBlurayExaminer _blurayExaminer;
private readonly ILocalizationManager _localization;
+ private readonly IApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization)
+ public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json)
{
_logger = logger;
_isoManager = isoManager;
@@ -37,9 +42,11 @@ namespace MediaBrowser.Providers.MediaInfo
_itemRepo = itemRepo;
_blurayExaminer = blurayExaminer;
_localization = localization;
+ _appPaths = appPaths;
+ _json = json;
}
- public async Task<ItemUpdateType> ProbeVideo<T>(T item, CancellationToken cancellationToken)
+ public async Task<ItemUpdateType> ProbeVideo<T>(T item, IDirectoryService directoryService, CancellationToken cancellationToken)
where T : Video
{
var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
@@ -66,7 +73,7 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
- await Fetch(item, cancellationToken, result, isoMount).ConfigureAwait(false);
+ await Fetch(item, cancellationToken, result, isoMount, directoryService).ConfigureAwait(false);
}
finally
@@ -84,6 +91,23 @@ namespace MediaBrowser.Providers.MediaInfo
{
cancellationToken.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var idString = item.Id.ToString("N");
+ var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-video", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+
+ try
+ {
+ return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ }
+ catch (FileNotFoundException)
+ {
+
+ }
+ catch (DirectoryNotFoundException)
+ {
+ }
+
var type = InputType.File;
var inputPath = isoMount == null ? new[] { item.Path } : new[] { isoMount.MountedPath };
@@ -94,10 +118,15 @@ namespace MediaBrowser.Providers.MediaInfo
inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type);
}
- return await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+ var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
+ _json.SerializeToFile(result, cachePath);
+
+ return result;
}
- protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount)
+ protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount, IDirectoryService directoryService)
{
if (data.format != null)
{
@@ -120,7 +149,7 @@ namespace MediaBrowser.Providers.MediaInfo
FetchBdInfo(video, chapters, mediaStreams, inputPath, cancellationToken);
}
- AddExternalSubtitles(video, mediaStreams);
+ AddExternalSubtitles(video, mediaStreams, directoryService);
FetchWtvInfo(video, data);
@@ -314,76 +343,104 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
+ public IEnumerable<FileInfo> GetSubtitleFiles(Video video, IDirectoryService directoryService)
+ {
+ var containingPath = video.ContainingFolderPath;
+
+ if (string.IsNullOrEmpty(containingPath))
+ {
+ throw new ArgumentException(string.Format("Cannot search for items that don't have a path: {0} {1}", video.Name, video.Id));
+ }
+
+ var files = directoryService.GetFiles(containingPath);
+
+ var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
+
+ return files.Where(i =>
+ {
+ if (!i.Attributes.HasFlag(FileAttributes.Directory) &&
+ SubtitleExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
+ {
+ var fullName = i.FullName;
+
+ var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
+
+ if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ }
+
/// <summary>
/// Adds the external subtitles.
/// </summary>
/// <param name="video">The video.</param>
/// <param name="currentStreams">The current streams.</param>
- private void AddExternalSubtitles(Video video, List<MediaStream> currentStreams)
+ private void AddExternalSubtitles(Video video, List<MediaStream> currentStreams, IDirectoryService directoryService)
{
- //var useParent = !video.ResolveArgs.IsDirectory;
-
- //if (useParent && video.Parent == null)
- //{
- // return;
- //}
-
- //var fileSystemChildren = useParent
- // ? video.Parent.ResolveArgs.FileSystemChildren
- // : video.ResolveArgs.FileSystemChildren;
-
- //var startIndex = currentStreams.Count;
- //var streams = new List<MediaStream>();
-
- //var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
-
- //foreach (var file in fileSystemChildren
- // .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && SubtitleExtensions.Contains(Path.GetExtension(f.FullName), StringComparer.OrdinalIgnoreCase)))
- //{
- // var fullName = file.FullName;
-
- // var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
-
- // // If the subtitle file matches the video file name
- // if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- // {
- // streams.Add(new MediaStream
- // {
- // Index = startIndex++,
- // Type = MediaStreamType.Subtitle,
- // IsExternal = true,
- // Path = fullName,
- // Codec = Path.GetExtension(fullName).ToLower().TrimStart('.')
- // });
- // }
- // else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
- // {
- // // Support xbmc naming conventions - 300.spanish.srt
- // var language = fileNameWithoutExtension.Split('.').LastOrDefault();
-
- // // Try to translate to three character code
- // // Be flexible and check against both the full and three character versions
- // var culture = _localization.GetCultures()
- // .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
-
- // if (culture != null)
- // {
- // language = culture.ThreeLetterISOLanguageName;
- // }
-
- // streams.Add(new MediaStream
- // {
- // Index = startIndex++,
- // Type = MediaStreamType.Subtitle,
- // IsExternal = true,
- // Path = fullName,
- // Codec = Path.GetExtension(fullName).ToLower().TrimStart('.'),
- // Language = language
- // });
- // }
- //}
-
- //currentStreams.AddRange(streams);
+ var files = GetSubtitleFiles(video, directoryService);
+
+ var startIndex = currentStreams.Count;
+ var streams = new List<MediaStream>();
+
+ var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
+
+ foreach (var file in files)
+ {
+ var fullName = file.FullName;
+
+ var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
+
+ // If the subtitle file matches the video file name
+ if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ streams.Add(new MediaStream
+ {
+ Index = startIndex++,
+ Type = MediaStreamType.Subtitle,
+ IsExternal = true,
+ Path = fullName,
+ Codec = Path.GetExtension(fullName).ToLower().TrimStart('.')
+ });
+ }
+ else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
+ {
+ // Support xbmc naming conventions - 300.spanish.srt
+ var language = fileNameWithoutExtension.Split('.').LastOrDefault();
+
+ // Try to translate to three character code
+ // Be flexible and check against both the full and three character versions
+ var culture = _localization.GetCultures()
+ .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
+
+ if (culture != null)
+ {
+ language = culture.ThreeLetterISOLanguageName;
+ }
+
+ streams.Add(new MediaStream
+ {
+ Index = startIndex++,
+ Type = MediaStreamType.Subtitle,
+ IsExternal = true,
+ Path = fullName,
+ Codec = Path.GetExtension(fullName).ToLower().TrimStart('.'),
+ Language = language
+ });
+ }
+ }
+
+ video.SubtitleFiles = streams.Select(i => i.Path).OrderBy(i => i).ToList();
+
+ currentStreams.AddRange(streams);
}
/// <summary>
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index 31d44f4ec..c230f65f9 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.MediaInfo
{
- public class VideoImageProvider : IDynamicImageProvider, IHasChangeMonitor
+ public class VideoImageProvider : IDynamicImageProvider, IHasChangeMonitor, IHasOrder
{
private readonly IIsoManager _isoManager;
private readonly IMediaEncoder _mediaEncoder;
@@ -126,9 +126,18 @@ namespace MediaBrowser.Providers.MediaInfo
return item.LocationType == LocationType.FileSystem && item is Video;
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
return item.DateModified > date;
}
+
+ public int Order
+ {
+ get
+ {
+ // Make sure this comes after internet image providers
+ return 100;
+ }
+ }
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/whitelist.txt b/MediaBrowser.Providers/MediaInfo/whitelist.txt
new file mode 100644
index 000000000..1fd366551
--- /dev/null
+++ b/MediaBrowser.Providers/MediaInfo/whitelist.txt
@@ -0,0 +1 @@
+AC/DC \ No newline at end of file