diff options
51 files changed, 765 insertions, 369 deletions
diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs index c0992a749..bb23f7f7e 100644 --- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs +++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs @@ -471,6 +471,76 @@ namespace MediaBrowser.Api.DefaultTheme }).Where(i => i != null).ToList(); } + private void SetFavoriteGenres(MoviesView view, IEnumerable<BaseItem> inputItems, User user) + { + var all = inputItems.SelectMany(i => i.Genres) + .Distinct(StringComparer.OrdinalIgnoreCase); + + view.FavoriteGenres = all.Select(i => + { + try + { + var itemByName = _libraryManager.GetGenre(i); + + var counts = itemByName.GetItemByNameCounts(user); + + var count = counts == null ? 0 : counts.MovieCount; + + if (count > 0 && _userDataManager.GetUserData(user.Id, itemByName.GetUserDataKey()).IsFavorite) + { + return new ItemByNameInfo + { + Name = itemByName.Name, + ItemCount = count + }; + } + } + catch (Exception ex) + { + _logger.ErrorException("Error getting genre {0}", ex, i); + + } + + return null; + + }).Where(i => i != null).ToList(); + } + + private void SetFavoriteStudios(MoviesView view, IEnumerable<BaseItem> inputItems, User user) + { + var all = inputItems.SelectMany(i => i.Studios) + .Distinct(StringComparer.OrdinalIgnoreCase); + + view.FavoriteStudios = all.Select(i => + { + try + { + var itemByName = _libraryManager.GetStudio(i); + + var counts = itemByName.GetItemByNameCounts(user); + + var count = counts == null ? 0 : counts.MovieCount; + + if (count > 0 && _userDataManager.GetUserData(user.Id, itemByName.GetUserDataKey()).IsFavorite) + { + return new ItemByNameInfo + { + Name = itemByName.Name, + ItemCount = count + }; + } + } + catch (Exception ex) + { + _logger.ErrorException("Error getting studio {0}", ex, i); + + } + + return null; + + }).Where(i => i != null).ToList(); + } + public object Get(GetMovieView request) { var user = _userManager.GetUserById(request.UserId); @@ -487,6 +557,9 @@ namespace MediaBrowser.Api.DefaultTheme var movies = items.OfType<Movie>() .ToList(); + SetFavoriteGenres(view, movies, user); + SetFavoriteStudios(view, movies, user); + var trailers = items.OfType<Trailer>() .ToList(); diff --git a/MediaBrowser.Api/DefaultTheme/Models.cs b/MediaBrowser.Api/DefaultTheme/Models.cs index 6dbd6b562..bdff82de2 100644 --- a/MediaBrowser.Api/DefaultTheme/Models.cs +++ b/MediaBrowser.Api/DefaultTheme/Models.cs @@ -34,6 +34,9 @@ namespace MediaBrowser.Api.DefaultTheme public List<BaseItemDto> LatestTrailers { get; set; } public List<BaseItemDto> LatestMovies { get; set; } + + public List<ItemByNameInfo> FavoriteGenres { get; set; } + public List<ItemByNameInfo> FavoriteStudios { get; set; } } public class TvView : BaseView diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 61259a4c2..0e5f420b5 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -861,21 +861,10 @@ namespace MediaBrowser.Api.Images Position = 0 }; - var imageIndex = 0; - - if (imageType == ImageType.Screenshot) - { - imageIndex = entity.ScreenshotImagePaths.Count; - } - else if (imageType == ImageType.Backdrop) - { - imageIndex = entity.BackdropImagePaths.Count; - } - // Handle image/png; charset=utf-8 mimeType = mimeType.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, imageIndex, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, null, null, CancellationToken.None).ConfigureAwait(false); await entity.RefreshMetadata(CancellationToken.None, forceRefresh: true, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index 0cf51abac..f92d9d581 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -282,14 +282,7 @@ namespace MediaBrowser.Api.Images /// <returns>Task.</returns> private async Task DownloadRemoteImage(BaseItem item, BaseDownloadRemoteImage request) { - int? index = null; - - if (request.Type == ImageType.Backdrop) - { - index = item.BackdropImagePaths.Count; - } - - await _providerManager.SaveImage(item, request.ImageUrl, null, request.Type, index, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, request.ImageUrl, null, request.Type, null, CancellationToken.None).ConfigureAwait(false); await item.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false) .ConfigureAwait(false); diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index ace8c4a6e..6e1dbc08b 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -219,8 +219,12 @@ namespace MediaBrowser.Api item.Budget = request.Budget; item.Revenue = request.Revenue; - item.CriticRating = request.CriticRating; - item.CriticRatingSummary = request.CriticRatingSummary; + var hasCriticRating = item as IHasCriticRating; + if (hasCriticRating != null) + { + hasCriticRating.CriticRating = request.CriticRating; + hasCriticRating.CriticRatingSummary = request.CriticRatingSummary; + } item.DisplayMediaType = request.DisplayMediaType; item.CommunityRating = request.CommunityRating; diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 29a894b1c..9547cc0a4 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -581,7 +581,17 @@ namespace MediaBrowser.Api.UserLibrary { var val = request.MinCriticRating.Value; - items = items.Where(i => i.CriticRating.HasValue && i.CriticRating >= val); + items = items.Where(i => + { + var hasCriticRating = i as IHasCriticRating; + + if (hasCriticRating != null) + { + return hasCriticRating.CriticRating.HasValue && hasCriticRating.CriticRating >= val; + } + + return false; + }); } // Artists diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 76a079c57..9222a8907 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -40,5 +40,37 @@ namespace MediaBrowser.Controller.Drawing public int? PercentPlayed { get; set; } public string BackgroundColor { get; set; } + + public bool HasDefaultOptions() + { + return HasDefaultOptionsWithoutSize() && + !Width.HasValue && + !Height.HasValue && + !MaxWidth.HasValue && + !MaxHeight.HasValue; + } + + public bool HasDefaultOptionsWithoutSize() + { + return !CropWhiteSpace && + (!Quality.HasValue || Quality.Value == 100) && + IsOutputFormatDefault && + !AddPlayedIndicator && + !PercentPlayed.HasValue && + string.IsNullOrEmpty(BackgroundColor); + } + + private bool IsOutputFormatDefault + { + get + { + if (OutputFormat == ImageOutputFormat.Original) + { + return true; + } + + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/Audio/Artist.cs b/MediaBrowser.Controller/Entities/Audio/Artist.cs index 5e14b0152..947ee1122 100644 --- a/MediaBrowser.Controller/Entities/Audio/Artist.cs +++ b/MediaBrowser.Controller/Entities/Audio/Artist.cs @@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.Entities.Audio } public string LastFmImageUrl { get; set; } + public string LastFmImageSize { get; set; } /// <summary> /// Gets the user data key. diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index b96cd625f..cb64cfdfe 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Entities.Audio } public string LastFmImageUrl { get; set; } + public string LastFmImageSize { get; set; } /// <summary> /// Songs will group into us so don't also include us in the index diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 75231ec6a..d791c92ae 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -11,6 +11,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// </summary> /// <value>The last fm image URL.</value> public string LastFmImageUrl { get; set; } + public string LastFmImageSize { get; set; } /// <summary> /// Gets the user data key. diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 839fe34ff..f8b2fad23 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -112,18 +112,6 @@ namespace MediaBrowser.Controller.Entities public double? Revenue { get; set; } /// <summary> - /// Gets or sets the critic rating. - /// </summary> - /// <value>The critic rating.</value> - public float? CriticRating { get; set; } - - /// <summary> - /// Gets or sets the critic rating summary. - /// </summary> - /// <value>The critic rating summary.</value> - public string CriticRatingSummary { get; set; } - - /// <summary> /// Gets or sets the trailer URL. /// </summary> /// <value>The trailer URL.</value> diff --git a/MediaBrowser.Controller/Entities/IHasCriticRating.cs b/MediaBrowser.Controller/Entities/IHasCriticRating.cs new file mode 100644 index 000000000..d2b93759d --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasCriticRating.cs @@ -0,0 +1,20 @@ +namespace MediaBrowser.Controller.Entities +{ + /// <summary> + /// Interface IHasCriticRating + /// </summary> + public interface IHasCriticRating + { + /// <summary> + /// Gets or sets the critic rating. + /// </summary> + /// <value>The critic rating.</value> + float? CriticRating { get; set; } + + /// <summary> + /// Gets or sets the critic rating summary. + /// </summary> + /// <value>The critic rating summary.</value> + string CriticRatingSummary { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 516ee9a8a..54ad9c1c9 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// <summary> /// Class Movie /// </summary> - public class Movie : Video + public class Movie : Video, IHasCriticRating { public List<Guid> SpecialFeatureIds { get; set; } @@ -21,6 +21,18 @@ namespace MediaBrowser.Controller.Entities.Movies } /// <summary> + /// Gets or sets the critic rating. + /// </summary> + /// <value>The critic rating.</value> + public float? CriticRating { get; set; } + + /// <summary> + /// Gets or sets the critic rating summary. + /// </summary> + /// <value>The critic rating summary.</value> + public string CriticRatingSummary { get; set; } + + /// <summary> /// Gets or sets the name of the TMDB collection. /// </summary> /// <value>The name of the TMDB collection.</value> diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index e7d47f7ec..c9fe471b3 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Trailer /// </summary> - public class Trailer : Video + public class Trailer : Video, IHasCriticRating { public Trailer() { @@ -16,6 +16,18 @@ namespace MediaBrowser.Controller.Entities } /// <summary> + /// Gets or sets the critic rating. + /// </summary> + /// <value>The critic rating.</value> + public float? CriticRating { get; set; } + + /// <summary> + /// Gets or sets the critic rating summary. + /// </summary> + /// <value>The critic rating summary.</value> + public string CriticRatingSummary { get; set; } + + /// <summary> /// Gets a value indicating whether this instance is local trailer. /// </summary> /// <value><c>true</c> if this instance is local trailer; otherwise, <c>false</c>.</value> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 978d56bd4..94ff5d305 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -89,6 +89,7 @@ <Compile Include="Entities\GameGenre.cs" /> <Compile Include="Entities\GameSystem.cs" /> <Compile Include="Entities\IByReferenceItem.cs" /> + <Compile Include="Entities\IHasCriticRating.cs" /> <Compile Include="Entities\IItemByName.cs" /> <Compile Include="Entities\ILibraryItem.cs" /> <Compile Include="Entities\ImageSourceInfo.cs" /> diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index e9bb7f66d..9fdbbf3b7 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -143,10 +143,16 @@ namespace MediaBrowser.Controller.Providers case "CriticRating": { var text = reader.ReadElementContentAsString(); - float value; - if (float.TryParse(text, NumberStyles.Any, _usCulture, out value)) + + var hasCriticRating = item as IHasCriticRating; + + if (hasCriticRating != null && !string.IsNullOrEmpty(text)) { - item.CriticRating = value; + float value; + if (float.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasCriticRating.CriticRating = value; + } } break; @@ -207,7 +213,12 @@ namespace MediaBrowser.Controller.Providers if (!string.IsNullOrWhiteSpace(val)) { - item.CriticRatingSummary = val; + var hasCriticRating = item as IHasCriticRating; + + if (hasCriticRating != null) + { + hasCriticRating.CriticRatingSummary = val; + } } break; diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index de7e8e98d..07bb7d5b2 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Controller.Providers /// </summary> /// <value>The logger.</value> protected ILogger Logger { get; set; } + protected ILogManager LogManager { get; set; } /// <summary> @@ -41,6 +42,7 @@ namespace MediaBrowser.Controller.Providers /// The true task result /// </summary> protected static readonly Task<bool> TrueTaskResult = Task.FromResult(true); + protected static readonly Task<bool> FalseTaskResult = Task.FromResult(false); protected static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(5, 5); @@ -132,7 +134,8 @@ namespace MediaBrowser.Controller.Providers /// <param name="providerVersion">The provider version.</param> /// <param name="status">The status.</param> /// <exception cref="System.ArgumentNullException">item</exception> - public virtual void SetLastRefreshed(BaseItem item, DateTime value, string providerVersion, ProviderRefreshStatus status = ProviderRefreshStatus.Success) + public virtual void SetLastRefreshed(BaseItem item, DateTime value, string providerVersion, + ProviderRefreshStatus status = ProviderRefreshStatus.Success) { if (item == null) { @@ -172,7 +175,8 @@ namespace MediaBrowser.Controller.Providers /// <param name="item">The item.</param> /// <param name="value">The value.</param> /// <param name="status">The status.</param> - public void SetLastRefreshed(BaseItem item, DateTime value, ProviderRefreshStatus status = ProviderRefreshStatus.Success) + public void SetLastRefreshed(BaseItem item, DateTime value, + ProviderRefreshStatus status = ProviderRefreshStatus.Success) { SetLastRefreshed(item, value, ProviderVersion, status); } @@ -238,7 +242,8 @@ namespace MediaBrowser.Controller.Providers return true; } - if (RefreshOnFileSystemStampChange && item.LocationType == LocationType.FileSystem && HasFileSystemStampChanged(item, providerInfo)) + if (RefreshOnFileSystemStampChange && item.LocationType == LocationType.FileSystem && + HasFileSystemStampChanged(item, providerInfo)) { return true; } @@ -349,21 +354,23 @@ namespace MediaBrowser.Controller.Providers } private Dictionary<string, string> _fileStampExtensionsDictionary; + private Dictionary<string, string> FileStampExtensionsDictionary { get { return _fileStampExtensionsDictionary ?? (_fileStampExtensionsDictionary = - FilestampExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase)); + FilestampExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase)); } } + /// <summary> /// Gets the file system stamp. /// </summary> /// <param name="item">The item.</param> /// <returns>Guid.</returns> - private Guid GetFileSystemStamp(BaseItem item) + protected virtual Guid GetFileSystemStamp(BaseItem item) { // If there's no path or the item is a file, there's nothing to do if (item.LocationType != LocationType.FileSystem) @@ -404,6 +411,20 @@ namespace MediaBrowser.Controller.Providers private static readonly Dictionary<string, string> FoldersToMonitor = new[] { "extrafanart", "extrathumbs" } .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + protected Guid GetFileSystemStamp(IEnumerable<FileSystemInfo> files) + { + var sb = new StringBuilder(); + + var extensions = FileStampExtensionsDictionary; + var numExtensions = FilestampExtensions.Length; + + // Record the name of each file + // Need to sort these because accoring to msdn docs, our i/o methods are not guaranteed in any order + AddFiles(sb, files, extensions, numExtensions); + + return sb.ToString().GetMD5(); + } + /// <summary> /// Adds the files. /// </summary> @@ -424,7 +445,7 @@ namespace MediaBrowser.Controller.Providers { sb.Append(file.Name); - var children = ((DirectoryInfo) file).EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList(); + var children = ((DirectoryInfo)file).EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList(); AddFiles(sb, children, extensions, numExtensions); } } diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs index fabe1b24c..e95b5e375 100644 --- a/MediaBrowser.Model/Drawing/DrawingUtils.cs +++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs @@ -1,4 +1,5 @@ - +using System.Globalization; + namespace MediaBrowser.Model.Drawing { /// <summary> @@ -131,15 +132,77 @@ namespace MediaBrowser.Model.Drawing /// </summary> public struct ImageSize { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + private double _height; + private double _width; + /// <summary> /// Gets or sets the height. /// </summary> /// <value>The height.</value> - public double Height { get; set; } + public double Height + { + get + { + return _height; + } + set + { + _height = value; + } + } + /// <summary> /// Gets or sets the width. /// </summary> /// <value>The width.</value> - public double Width { get; set; } + public double Width + { + get { return _width; } + set { _width = value; } + } + + public bool Equals(ImageSize size) + { + return Width.Equals(size.Width) && Height.Equals(size.Height); + } + + public override string ToString() + { + return string.Format("{0}-{1}", Width, Height); + } + + public ImageSize(string value) + { + _width = 0; + + _height = 0; + + ParseValue(value); + } + + private void ParseValue(string value) + { + if (!string.IsNullOrEmpty(value)) + { + var parts = value.Split('-'); + + if (parts.Length == 2) + { + double val; + + if (double.TryParse(parts[0], NumberStyles.Any, UsCulture, out val)) + { + _width = val; + } + + if (double.TryParse(parts[1], NumberStyles.Any, UsCulture, out val)) + { + _height = val; + } + } + } + } } } diff --git a/MediaBrowser.Providers/CollectionFolderImageProvider.cs b/MediaBrowser.Providers/CollectionFolderImageProvider.cs new file mode 100644 index 000000000..45b1b36c2 --- /dev/null +++ b/MediaBrowser.Providers/CollectionFolderImageProvider.cs @@ -0,0 +1,55 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Providers +{ + public class CollectionFolderImageProvider : ImageFromMediaLocationProvider + { + public CollectionFolderImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) + : base(logManager, configurationManager, fileSystem) + { + } + + public override bool Supports(BaseItem item) + { + return item is CollectionFolder && item.LocationType == LocationType.FileSystem; + } + + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Second; } + } + + protected override FileSystemInfo GetImage(BaseItem item, ItemResolveArgs args, string filenameWithoutExtension) + { + return item.ResolveArgs.PhysicalLocations + .Select(i => GetImageFromLocation(i, filenameWithoutExtension)) + .FirstOrDefault(i => i != null); + } + + protected override Guid GetFileSystemStamp(BaseItem item) + { + var files = item.ResolveArgs.PhysicalLocations + .Select(i => new DirectoryInfo(i)) + .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) + .Where(i => + { + var ext = i.Extension; + + return !string.IsNullOrEmpty(ext) && + BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase); + }) + .ToList(); + + return GetFileSystemStamp(files); + } + } +} diff --git a/MediaBrowser.Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Providers/ImageFromMediaLocationProvider.cs index 9943c7ab8..aa0dcc9d4 100644 --- a/MediaBrowser.Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Providers/ImageFromMediaLocationProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; @@ -21,9 +22,12 @@ namespace MediaBrowser.Providers /// </summary> public class ImageFromMediaLocationProvider : BaseMetadataProvider { - public ImageFromMediaLocationProvider(ILogManager logManager, IServerConfigurationManager configurationManager) + protected readonly IFileSystem FileSystem; + + public ImageFromMediaLocationProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) : base(logManager, configurationManager) { + FileSystem = fileSystem; } public override ItemUpdateType ItemUpdateType @@ -543,5 +547,37 @@ namespace MediaBrowser.Providers item.ScreenshotImagePaths = screenshotFiles; } } + + protected FileSystemInfo GetImageFromLocation(string path, string filenameWithoutExtension) + { + try + { + var files = new DirectoryInfo(path) + .EnumerateFiles() + .Where(i => + { + var fileName = Path.GetFileNameWithoutExtension(i.FullName); + + if (!string.Equals(fileName, filenameWithoutExtension, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var ext = i.Extension; + + return !string.IsNullOrEmpty(ext) && + BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase); + }) + .ToList(); + + return BaseItem.SupportedImageExtensions + .Select(ext => files.FirstOrDefault(i => string.Equals(ext, i.Extension, StringComparison.OrdinalIgnoreCase))) + .FirstOrDefault(file => file != null); + } + catch (DirectoryNotFoundException) + { + return null; + } + } } } diff --git a/MediaBrowser.Providers/ImagesByNameProvider.cs b/MediaBrowser.Providers/ImagesByNameProvider.cs index 6be4ee108..590430823 100644 --- a/MediaBrowser.Providers/ImagesByNameProvider.cs +++ b/MediaBrowser.Providers/ImagesByNameProvider.cs @@ -1,16 +1,12 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System; using System.IO; using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers { @@ -19,22 +15,11 @@ namespace MediaBrowser.Providers /// </summary> public class ImagesByNameProvider : ImageFromMediaLocationProvider { - private readonly IFileSystem _fileSystem; - public ImagesByNameProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) - : base(logManager, configurationManager) + : base(logManager, configurationManager, fileSystem) { - _fileSystem = fileSystem; } - public override ItemUpdateType ItemUpdateType - { - get - { - return ItemUpdateType.ImageUpdate; - } - } - /// <summary> /// Supportses the specified item. /// </summary> @@ -42,8 +27,8 @@ namespace MediaBrowser.Providers /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> public override bool Supports(BaseItem item) { - //only run for these generic types since we are expensive in file i/o - return item is IndexFolder || item is BasePluginFolder || item is CollectionFolder; + // Only run for these generic types since we are expensive in file i/o + return item is BasePluginFolder || item is CollectionFolder; } /// <summary> @@ -59,102 +44,13 @@ namespace MediaBrowser.Providers } /// <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) - { - // Force a refresh if the IBN path changed - if (providerInfo.FileStamp != ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5()) - { - return true; - } - - return base.NeedsRefreshInternal(item, providerInfo); - } - - /// <summary> - /// Gets a value indicating whether [refresh on file system stamp change]. - /// </summary> - /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value> - protected override bool RefreshOnFileSystemStampChange - { - get - { - return false; - } - } - - /// <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) - { - // If the IBN location exists return the last modified date of any file in it - var location = GetLocation(item); - - var directoryInfo = new DirectoryInfo(location); - - if (!directoryInfo.Exists) - { - return DateTime.MinValue; - } - - var files = directoryInfo.EnumerateFiles().ToList(); - - if (files.Count == 0) - { - return DateTime.MinValue; - } - - return files.Select(f => - { - var lastWriteTime = _fileSystem.GetLastWriteTimeUtc(f); - var creationTime = _fileSystem.GetCreationTimeUtc(f); - - return creationTime > lastWriteTime ? creationTime : lastWriteTime; - - }).Max(); - } - - /// <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 result = await base.FetchAsync(item, force, cancellationToken).ConfigureAwait(false); - - BaseProviderInfo data; - - if (!item.ProviderData.TryGetValue(Id, out data)) - { - data = new BaseProviderInfo(); - item.ProviderData[Id] = data; - } - - data.FileStamp = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5(); - SetLastRefreshed(item, DateTime.UtcNow); - - return result; - } - - /// <summary> /// Gets the location. /// </summary> /// <param name="item">The item.</param> /// <returns>System.String.</returns> protected string GetLocation(BaseItem item) { - var name = _fileSystem.GetValidFilename(item.Name); + var name = FileSystem.GetValidFilename(item.Name); return Path.Combine(ConfigurationManager.ApplicationPaths.GeneralPath, name); } @@ -170,30 +66,34 @@ namespace MediaBrowser.Providers { var location = GetLocation(item); - var directoryInfo = new DirectoryInfo(location); - - if (!directoryInfo.Exists) - { - return null; - } - - var files = directoryInfo.EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList(); + return GetImageFromLocation(location, filenameWithoutExtension); + } - var file = files.FirstOrDefault(i => string.Equals(i.Name, filenameWithoutExtension + ".png", StringComparison.OrdinalIgnoreCase)); + protected override Guid GetFileSystemStamp(BaseItem item) + { + var location = GetLocation(item); - if (file != null) + try { - return file; + var files = new DirectoryInfo(location) + .EnumerateFiles("*", SearchOption.TopDirectoryOnly) + .Where(i => + { + var ext = i.Extension; + + return !string.IsNullOrEmpty(ext) && + BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase); + }) + .ToList(); + + return GetFileSystemStamp(files); } - - file = files.FirstOrDefault(i => string.Equals(i.Name, filenameWithoutExtension + ".jpg", StringComparison.OrdinalIgnoreCase)); - - if (file != null) + catch (DirectoryNotFoundException) { - return file; - } + // User doesn't have the folder. No need to log or blow up - return null; + return Guid.Empty; + } } } } diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index f4d0ad7eb..ad5dd9b3f 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -47,6 +47,7 @@ </Reference> </ItemGroup> <ItemGroup> + <Compile Include="CollectionFolderImageProvider.cs" /> <Compile Include="FanartBaseProvider.cs" /> <Compile Include="FolderProviderFromXml.cs" /> <Compile Include="Games\GameXmlParser.cs" /> @@ -92,6 +93,7 @@ <Compile Include="Music\AlbumDynamicInfoProvider.cs" /> <Compile Include="Music\ManualFanartAlbumProvider.cs" /> <Compile Include="Music\ManualFanartArtistProvider.cs" /> + <Compile Include="Music\ManualLastFmImageProvider.cs" /> <Compile Include="Music\MusicVideoXmlParser.cs" /> <Compile Include="Music\SoundtrackPostScanTask.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> diff --git a/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs index 323fa20e6..f65bf9ea3 100644 --- a/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs @@ -251,17 +251,33 @@ namespace MediaBrowser.Providers.MediaInfo private string GetAspectRatio(MediaStreamInfo info) { - if (info.height > 0 && info.width > 0) + var original = info.display_aspect_ratio; + + int height; + int width; + + var parts = (original ?? string.Empty).Split(':'); + if (!(parts.Length == 2 && + int.TryParse(parts[0], NumberStyles.Any, UsCulture, out width) && + int.TryParse(parts[1], NumberStyles.Any, UsCulture, out height) && + width > 0 && + height > 0)) + { + width = info.width; + height = info.height; + } + + if (width > 0 && height > 0) { - double ratio = info.width; - ratio /= info.height; + double ratio = width; + ratio /= height; - if (IsClose(ratio, 1.777777778)) + if (IsClose(ratio, 1.777777778, .03)) { return "16:9"; } - if (IsClose(ratio, 1.3333333333)) + if (IsClose(ratio, 1.3333333333, .05)) { return "4:3"; } @@ -286,31 +302,30 @@ namespace MediaBrowser.Providers.MediaInfo return "5:3"; } - if (IsClose(ratio, 1.85)) + if (IsClose(ratio, 1.85, .02)) { return "1.85:1"; } - if (IsClose(ratio, 2.39)) + if (IsClose(ratio, 2.35, .025)) { - return "2.39:1"; + return "2.35:1"; } - if (IsClose(ratio, 2.4)) + if (IsClose(ratio, 2.4, .025)) { - return "2.4:1"; + return "2.40:1"; } } - return info.display_aspect_ratio; + return original; } - private bool IsClose(double d1, double d2) + private bool IsClose(double d1, double d2, double variance = .005) { - return Math.Abs(d1 - d2) <= .005; + return Math.Abs(d1 - d2) <= variance; } - /// <summary> /// Gets a frame rate from a string value in ffprobe output /// This could be a number or in the format of 2997/125. diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 24f17556b..39908c3ee 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -327,15 +327,11 @@ namespace MediaBrowser.Providers.Movies if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) { - var numBackdrops = item.BackdropImagePaths.Count; - foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) .ConfigureAwait(false); - numBackdrops++; - if (item.BackdropImagePaths.Count >= backdropLimit) break; } } diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index ab6dbf6d4..d2a12ac21 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -231,7 +231,7 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false); - await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Backdrop, item.BackdropImagePaths.Count, url, cancellationToken) + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Backdrop, null, url, cancellationToken) .ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 9d71fef0a..cc6e07d62 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -822,13 +822,18 @@ namespace MediaBrowser.Providers.Movies // genres // Movies get this from imdb - if (movieData.genres != null && !movie.LockedFields.Contains(MetadataFields.Genres) && movie is BoxSet) + if (movieData.genres != null && !movie.LockedFields.Contains(MetadataFields.Genres)) { - movie.Genres.Clear(); - - foreach (var genre in movieData.genres.Select(g => g.name)) + // Only grab them if a boxset or there are no genres. + // For movies and trailers we'll use imdb via omdb + if (movie is BoxSet || movie.Genres.Count == 0) { - movie.AddGenre(genre); + movie.Genres.Clear(); + + foreach (var genre in movieData.genres.Select(g => g.name)) + { + movie.AddGenre(genre); + } } } diff --git a/MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs b/MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs index a6fdbdcef..6550396e5 100644 --- a/MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs +++ b/MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs @@ -139,22 +139,26 @@ namespace MediaBrowser.Providers.Movies { var result = JsonSerializer.DeserializeFromStream<RootObject>(stream); - // Seeing some bogus RT data on omdb for series, so filter it out here - // RT doesn't even have tv series - int tomatoMeter; - - if (!string.IsNullOrEmpty(result.tomatoMeter) - && int.TryParse(result.tomatoMeter, NumberStyles.Integer, UsCulture, out tomatoMeter) - && tomatoMeter >= 0) - { - item.CriticRating = tomatoMeter; - } - - if (!string.IsNullOrEmpty(result.tomatoConsensus) - && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase) - && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase)) + var hasCriticRating = item as IHasCriticRating; + if (hasCriticRating != null) { - item.CriticRatingSummary = result.tomatoConsensus; + // Seeing some bogus RT data on omdb for series, so filter it out here + // RT doesn't even have tv series + int tomatoMeter; + + if (!string.IsNullOrEmpty(result.tomatoMeter) + && int.TryParse(result.tomatoMeter, NumberStyles.Integer, UsCulture, out tomatoMeter) + && tomatoMeter >= 0) + { + hasCriticRating.CriticRating = tomatoMeter; + } + + if (!string.IsNullOrEmpty(result.tomatoConsensus) + && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase) + && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase)) + { + hasCriticRating.CriticRatingSummary = result.tomatoConsensus; + } } int voteCount; diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index 51adbc785..6df21b61d 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -8,17 +8,14 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Net; using System.Threading; using System.Threading.Tasks; -using System.Xml; namespace MediaBrowser.Providers.Music { @@ -323,15 +320,11 @@ namespace MediaBrowser.Providers.Music if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) { - var numBackdrops = item.BackdropImagePaths.Count; - foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) .ConfigureAwait(false); - numBackdrops++; - if (item.BackdropImagePaths.Count >= backdropLimit) break; } } diff --git a/MediaBrowser.Providers/Music/LastFmImageProvider.cs b/MediaBrowser.Providers/Music/LastFmImageProvider.cs index 5078326af..cd4005223 100644 --- a/MediaBrowser.Providers/Music/LastFmImageProvider.cs +++ b/MediaBrowser.Providers/Music/LastFmImageProvider.cs @@ -4,7 +4,10 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -55,11 +58,6 @@ namespace MediaBrowser.Providers.Music return false; } - if (string.IsNullOrWhiteSpace(GetImageUrl(item))) - { - return false; - } - return base.NeedsRefreshInternal(item, providerInfo); } @@ -72,56 +70,44 @@ namespace MediaBrowser.Providers.Music /// <returns>Task{System.Boolean}.</returns> public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - var url = GetImageUrl(item); - - if (!string.IsNullOrWhiteSpace(url) && !item.HasImage(ImageType.Primary)) + if (!item.HasImage(ImageType.Primary)) { - await _providerManager.SaveImage(item, url, LastfmBaseProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken) - .ConfigureAwait(false); + var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualLastFmImageProvider.ProviderName).ConfigureAwait(false); + + await DownloadImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); } SetLastRefreshed(item, DateTime.UtcNow); + return true; } - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public override MetadataProviderPriority Priority + private async Task DownloadImages(BaseItem item, List<RemoteImageInfo> images, CancellationToken cancellationToken) { - get { return MetadataProviderPriority.Fifth; } - } + cancellationToken.ThrowIfCancellationRequested(); - /// <summary> - /// Gets the image URL. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - private string GetImageUrl(BaseItem item) - { - var musicArtist = item as MusicArtist; - - if (musicArtist != null) - { - return musicArtist.LastFmImageUrl; - } + var configSetting = item is MusicAlbum + ? ConfigurationManager.Configuration.DownloadMusicAlbumImages + : ConfigurationManager.Configuration.DownloadMusicArtistImages; - var artistByName = item as Artist; - - if (artistByName != null) + if (configSetting.Primary && !item.HasImage(ImageType.Primary)) { - return artistByName.LastFmImageUrl; - } + var image = images.FirstOrDefault(i => i.Type == ImageType.Primary); - var album = item as MusicAlbum; - - if (album != null) - { - return album.LastFmImageUrl; + if (image != null) + { + await _providerManager.SaveImage(item, image.Url, LastfmBaseProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); + } } + } - return null; + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Fifth; } } } } diff --git a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs index 7192b5949..d0e807a86 100644 --- a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.Music { get { - return "8"; + return "9"; } } diff --git a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs index 7d83c3f6f..146992039 100644 --- a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.Music { get { - return "8"; + return "9"; } } diff --git a/MediaBrowser.Providers/Music/LastfmHelper.cs b/MediaBrowser.Providers/Music/LastfmHelper.cs index ae849b418..f529fd44a 100644 --- a/MediaBrowser.Providers/Music/LastfmHelper.cs +++ b/MediaBrowser.Providers/Music/LastfmHelper.cs @@ -34,21 +34,27 @@ namespace MediaBrowser.Providers.Music var musicArtist = artist as MusicArtist; + string imageSize; + if (musicArtist != null) { - musicArtist.LastFmImageUrl = GetImageUrl(data); + musicArtist.LastFmImageUrl = GetImageUrl(data, out imageSize); + musicArtist.LastFmImageSize = imageSize; } var artistByName = artist as Artist; if (artistByName != null) { - artistByName.LastFmImageUrl = GetImageUrl(data); + artistByName.LastFmImageUrl = GetImageUrl(data, out imageSize); + artistByName.LastFmImageSize = imageSize; } } - private static string GetImageUrl(IHasLastFmImages data) + private static string GetImageUrl(IHasLastFmImages data, out string size) { + size = null; + if (data.image == null) { return null; @@ -61,12 +67,13 @@ namespace MediaBrowser.Providers.Music var img = validImages .FirstOrDefault(i => string.Equals(i.size, "mega", StringComparison.OrdinalIgnoreCase)) ?? data.image.FirstOrDefault(i => string.Equals(i.size, "extralarge", StringComparison.OrdinalIgnoreCase)) ?? - data.image.FirstOrDefault(i => string.Equals(i.size, "large", StringComparison.OrdinalIgnoreCase)) ?? - data.image.FirstOrDefault(i => string.Equals(i.size, "medium", StringComparison.OrdinalIgnoreCase)) ?? + data.image.FirstOrDefault(i => string.Equals(i.size, "large", StringComparison.OrdinalIgnoreCase)) ?? + data.image.FirstOrDefault(i => string.Equals(i.size, "medium", StringComparison.OrdinalIgnoreCase)) ?? data.image.FirstOrDefault(); if (img != null) { + size = img.size; return img.url; } @@ -81,7 +88,7 @@ namespace MediaBrowser.Providers.Music target.Overview = source.Overview; target.ProductionLocations = source.ProductionLocations.ToList(); } - + public static void ProcessAlbumData(BaseItem item, LastfmAlbum data) { if (!string.IsNullOrWhiteSpace(data.mbid)) item.SetProviderId(MetadataProviders.Musicbrainz, data.mbid); @@ -107,7 +114,11 @@ namespace MediaBrowser.Providers.Music } var album = (MusicAlbum)item; - album.LastFmImageUrl = GetImageUrl(data); + + string imageSize; + + album.LastFmImageUrl = GetImageUrl(data, out imageSize); + album.LastFmImageSize = imageSize; } private static void AddTags(BaseItem item, LastfmTags tags) diff --git a/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs b/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs index bd79da15c..d95365b02 100644 --- a/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs @@ -325,7 +325,7 @@ namespace MediaBrowser.Providers.Music public int Priority { - get { return 0; } + get { return 1; } } } } diff --git a/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs b/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs index 2e4dbe813..6ff891f60 100644 --- a/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs +++ b/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs @@ -334,7 +334,7 @@ namespace MediaBrowser.Providers.Music public int Priority { - get { return 0; } + get { return 1; } } } } diff --git a/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs b/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs new file mode 100644 index 000000000..0b1b95b1e --- /dev/null +++ b/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs @@ -0,0 +1,110 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Music +{ + public class ManualLastFmImageProvider : IImageProvider + { + public string Name + { + get { return ProviderName; } + } + + public static string ProviderName + { + get { return "last.fm"; } + } + + public bool Supports(BaseItem item) + { + return item is MusicAlbum || item is MusicArtist || item is Artist; + } + + public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken) + { + var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); + + return images.Where(i => i.Type == imageType); + } + + public Task<IEnumerable<RemoteImageInfo>> GetAllImages(BaseItem item, CancellationToken cancellationToken) + { + var list = new List<RemoteImageInfo>(); + + RemoteImageInfo info = null; + + var artist = item as Artist; + + if (artist != null) + { + info = GetInfo(artist.LastFmImageUrl, artist.LastFmImageSize); + } + + var album = item as MusicAlbum; + if (album != null) + { + info = GetInfo(album.LastFmImageUrl, album.LastFmImageSize); + } + + var musicArtist = item as MusicArtist; + if (musicArtist != null) + { + info = GetInfo(musicArtist.LastFmImageUrl, musicArtist.LastFmImageSize); + } + + if (info != null) + { + list.Add(info); + } + + // The only info we have is size + return Task.FromResult<IEnumerable<RemoteImageInfo>>(list.OrderByDescending(i => i.Width ?? 0)); + } + + private RemoteImageInfo GetInfo(string url, string size) + { + if (string.IsNullOrEmpty(url)) + { + return null; + } + + var info = new RemoteImageInfo + { + ProviderName = Name, + Url = url + }; + + if (string.Equals(size, "mega", StringComparison.OrdinalIgnoreCase)) + { + + } + else if (string.Equals(size, "extralarge", StringComparison.OrdinalIgnoreCase)) + { + + } + else if (string.Equals(size, "large", StringComparison.OrdinalIgnoreCase)) + { + + } + else if (string.Equals(size, "medium", StringComparison.OrdinalIgnoreCase)) + { + + } + + return info; + } + + public int Priority + { + get { return 0; } + } + } +} diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index d9e0fb6e2..69276e0b8 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -209,14 +209,18 @@ namespace MediaBrowser.Providers.Savers builder.Append("<Type>" + SecurityElement.Escape(item.DisplayMediaType) + "</Type>"); } - if (item.CriticRating.HasValue) + var hasCriticRating = item as IHasCriticRating; + if (hasCriticRating != null) { - builder.Append("<CriticRating>" + SecurityElement.Escape(item.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>"); - } + if (hasCriticRating.CriticRating.HasValue) + { + builder.Append("<CriticRating>" + SecurityElement.Escape(hasCriticRating.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>"); + } - if (!string.IsNullOrEmpty(item.CriticRatingSummary)) - { - builder.Append("<CriticRatingSummary><![CDATA[" + item.CriticRatingSummary + "]]></CriticRatingSummary>"); + if (!string.IsNullOrEmpty(hasCriticRating.CriticRatingSummary)) + { + builder.Append("<CriticRatingSummary><![CDATA[" + hasCriticRating.CriticRatingSummary + "]]></CriticRatingSummary>"); + } } if (!string.IsNullOrEmpty(item.Overview)) diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs index 31f8f9cb4..1f20140c5 100644 --- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs @@ -260,15 +260,11 @@ namespace MediaBrowser.Providers.TV if (ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) { - var numBackdrops = item.BackdropImagePaths.Count; - foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) .ConfigureAwait(false); - numBackdrops++; - if (item.BackdropImagePaths.Count >= backdropLimit) break; } } diff --git a/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs index 77a432add..05fee7861 100644 --- a/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs @@ -181,8 +181,6 @@ namespace MediaBrowser.Providers.TV if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) { - var bdNo = item.BackdropImagePaths.Count; - foreach (var backdrop in images.Where(i => i.Type == ImageType.Backdrop)) { var url = backdrop.Url; @@ -192,9 +190,7 @@ namespace MediaBrowser.Providers.TV continue; } - await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken).ConfigureAwait(false); - - bdNo++; + await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, null, cancellationToken).ConfigureAwait(false); if (item.BackdropImagePaths.Count >= backdropLimit) break; } diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 42118c063..b56b50bec 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -191,8 +191,6 @@ namespace MediaBrowser.Providers.TV if (ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) { - var bdNo = item.BackdropImagePaths.Count; - foreach (var backdrop in images.Where(i => i.Type == ImageType.Backdrop && (!i.Width.HasValue || i.Width.Value >= ConfigurationManager.Configuration.MinSeriesBackdropDownloadWidth))) @@ -204,9 +202,7 @@ namespace MediaBrowser.Providers.TV continue; } - await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken).ConfigureAwait(false); - - bdNo++; + await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, null, cancellationToken).ConfigureAwait(false); if (item.BackdropImagePaths.Count >= backdropLimit) break; } diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index a439251db..78dcf6fd0 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -3,11 +3,11 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -25,7 +25,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <summary> /// Class ImageProcessor /// </summary> - public class ImageProcessor : IImageProcessor + public class ImageProcessor : IImageProcessor, IDisposable { /// <summary> /// The us culture @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <summary> /// The _cached imaged sizes /// </summary> - private readonly ConcurrentDictionary<string, ImageSize> _cachedImagedSizes = new ConcurrentDictionary<string, ImageSize>(); + private readonly ConcurrentDictionary<Guid, ImageSize> _cachedImagedSizes; /// <summary> /// Gets the list of currently registered image processors @@ -50,21 +50,41 @@ namespace MediaBrowser.Server.Implementations.Drawing private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _jsonSerializer; + private readonly IServerApplicationPaths _appPaths; private readonly string _imageSizeCachePath; private readonly string _croppedWhitespaceImageCachePath; private readonly string _enhancedImageCachePath; private readonly string _resizedImageCachePath; - public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem) + public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer) { _logger = logger; _fileSystem = fileSystem; + _jsonSerializer = jsonSerializer; + _appPaths = appPaths; _imageSizeCachePath = Path.Combine(appPaths.ImageCachePath, "image-sizes"); _croppedWhitespaceImageCachePath = Path.Combine(appPaths.ImageCachePath, "cropped-images"); _enhancedImageCachePath = Path.Combine(appPaths.ImageCachePath, "enhanced-images"); _resizedImageCachePath = Path.Combine(appPaths.ImageCachePath, "resized-images"); + + _saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite); + + Dictionary<Guid, ImageSize> sizeDictionary; + + try + { + sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile); + } + catch (IOException) + { + // No biggie + sizeDictionary = new Dictionary<Guid, ImageSize>(); + } + + _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary); } public void AddParts(IEnumerable<IImageEnhancer> enhancers) @@ -85,6 +105,17 @@ namespace MediaBrowser.Server.Implementations.Drawing } var originalImagePath = options.OriginalImagePath; + + if (options.HasDefaultOptions()) + { + // Just spit out the original file if all the options are default + using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + { + await fileStream.CopyToAsync(toStream).ConfigureAwait(false); + return; + } + } + var dateModified = options.OriginalImageDateModified; if (options.CropWhiteSpace) @@ -106,6 +137,16 @@ namespace MediaBrowser.Server.Implementations.Drawing // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); + if (options.HasDefaultOptionsWithoutSize() && newSize.Equals(originalImageSize)) + { + // Just spit out the original file the new size equals the old + using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + { + await fileStream.CopyToAsync(toStream).ConfigureAwait(false); + return; + } + } + var quality = options.Quality ?? 90; var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.BackgroundColor); @@ -465,11 +506,13 @@ namespace MediaBrowser.Server.Implementations.Drawing ImageSize size; - if (!_cachedImagedSizes.TryGetValue(name, out size)) + var cacheHash = name.GetMD5(); + + if (!_cachedImagedSizes.TryGetValue(cacheHash, out size)) { - size = GetImageSizeInternal(name, path); + size = GetImageSizeInternal(path); - _cachedImagedSizes.AddOrUpdate(name, size, (keyName, oldValue) => size); + _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size); } return size; @@ -478,62 +521,47 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <summary> /// Gets the image size internal. /// </summary> - /// <param name="cacheKey">The cache key.</param> /// <param name="path">The path.</param> /// <returns>ImageSize.</returns> - private ImageSize GetImageSizeInternal(string cacheKey, string path) + private ImageSize GetImageSizeInternal(string path) { - // Now check the file system cache - var fullCachePath = GetCachePath(_imageSizeCachePath, cacheKey, ".txt"); + var size = ImageHeader.GetDimensions(path, _logger, _fileSystem); - try - { - var result = File.ReadAllText(fullCachePath).Split('|'); + StartSaveImageSizeTimer(); - return new ImageSize - { - Width = double.Parse(result[0], UsCulture), - Height = double.Parse(result[1], UsCulture) - }; - } - catch (IOException) - { - // Cache file doesn't exist or is currently being written to - } + return new ImageSize { Width = size.Width, Height = size.Height }; + } - var syncLock = GetObjectLock(fullCachePath); + private readonly Timer _saveImageSizeTimer; + private const int SaveImageSizeTimeout = 5000; + private readonly object _saveImageSizeLock = new object(); + private void StartSaveImageSizeTimer() + { + _saveImageSizeTimer.Change(SaveImageSizeTimeout, Timeout.Infinite); + } - lock (syncLock) + private void SaveImageSizeCallback(object state) + { + lock (_saveImageSizeLock) { try { - var result = File.ReadAllText(fullCachePath).Split('|'); - - return new ImageSize - { - Width = double.Parse(result[0], UsCulture), - Height = double.Parse(result[1], UsCulture) - }; - } - catch (FileNotFoundException) - { - // Cache file doesn't exist no biggie + var path = ImageSizeFile; + Directory.CreateDirectory(Path.GetDirectoryName(path)); + _jsonSerializer.SerializeToFile(_cachedImagedSizes, path); } - catch (DirectoryNotFoundException) + catch (Exception ex) { - // Cache file doesn't exist no biggie + _logger.ErrorException("Error saving image size file", ex); } + } + } - var size = ImageHeader.GetDimensions(path, _logger, _fileSystem); - - var parentPath = Path.GetDirectoryName(fullCachePath); - - Directory.CreateDirectory(parentPath); - - // Update the file system cache - File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture)); - - return new ImageSize { Width = size.Width, Height = size.Height }; + private string ImageSizeFile + { + get + { + return Path.Combine(_appPaths.DataPath, "imagesizes.json"); } } @@ -862,5 +890,10 @@ namespace MediaBrowser.Server.Implementations.Drawing }).ToList(); } + + public void Dispose() + { + _saveImageSizeTimer.Dispose(); + } } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 19e19f8ea..0104196e0 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -792,11 +792,15 @@ namespace MediaBrowser.Server.Implementations.Dto dto.MediaType = item.MediaType; dto.LocationType = item.LocationType; - dto.CriticRating = item.CriticRating; - - if (fields.Contains(ItemFields.CriticRatingSummary)) + var hasCriticRating = item as IHasCriticRating; + if (hasCriticRating != null) { - dto.CriticRatingSummary = item.CriticRatingSummary; + dto.CriticRating = hasCriticRating.CriticRating; + + if (fields.Contains(ItemFields.CriticRatingSummary)) + { + dto.CriticRatingSummary = hasCriticRating.CriticRatingSummary; + } } var localTrailerCount = item.LocalTrailerIds.Count; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs index 5f354fb0d..7d049549b 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs @@ -181,6 +181,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// <param name="dto">The dto.</param> private void FilterResponse(IHttpRequest req, IHttpResponse res, object dto) { + // Try to prevent compatibility view + res.AddHeader("X-UA-Compatible", "IE=Edge"); + var exception = dto as Exception; if (exception != null) diff --git a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs index 9fc622c21..a8c923bb0 100644 --- a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs @@ -363,6 +363,7 @@ namespace MediaBrowser.Server.Implementations.IO { if (string.Equals(i, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); return true; } @@ -370,6 +371,7 @@ namespace MediaBrowser.Server.Implementations.IO var parent = Path.GetDirectoryName(i); if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); return true; } @@ -379,10 +381,18 @@ namespace MediaBrowser.Server.Implementations.IO parent = Path.GetDirectoryName(i); if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); return true; } } + if (i.StartsWith(e.FullPath, StringComparison.OrdinalIgnoreCase) || + e.FullPath.StartsWith(i, StringComparison.OrdinalIgnoreCase)) + { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); + return true; + } + return false; })) @@ -390,12 +400,6 @@ namespace MediaBrowser.Server.Implementations.IO return; } - if (tempIgnorePaths.Contains(e.FullPath, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Watcher requested to ignore change to " + e.FullPath); - return; - } - Logger.Info("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath); //Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs index f46498599..0ed46e761 100644 --- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs +++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -8,6 +7,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -70,6 +70,15 @@ namespace MediaBrowser.Server.Implementations.Providers throw new ArgumentNullException("mimeType"); } + if (type == ImageType.Backdrop && imageIndex == null) + { + imageIndex = item.BackdropImagePaths.Count; + } + else if (type == ImageType.Screenshot && imageIndex == null) + { + imageIndex = item.ScreenshotImagePaths.Count; + } + var saveLocally = _config.Configuration.SaveLocalMeta && item.Parent != null && !(item is Audio); if (item is IItemByName || item is User) diff --git a/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs index 9484130cb..d01f7ed1b 100644 --- a/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs @@ -22,7 +22,9 @@ namespace MediaBrowser.Server.Implementations.Sorting private float GetValue(BaseItem x) { - return x.CriticRating ?? 0; + var hasCriticRating = x as IHasCriticRating; + + return hasCriticRating == null ? 0 : hasCriticRating.CriticRating ?? 0; } /// <summary> diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config index 4f60de145..ba6d74214 100644 --- a/MediaBrowser.ServerApplication/App.config +++ b/MediaBrowser.ServerApplication/App.config @@ -19,6 +19,7 @@ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <runtime> + <gcAllowVeryLargeObjects enabled="true" /> <gcServer enabled="true" /> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index c5c5bc7e5..03819ff91 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.ServerApplication LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LocalizationManager); - ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager); + ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); RegisterSingleInstance(ImageProcessor); DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor); diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index be821922f..b18d4c18a 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -375,9 +375,9 @@ namespace MediaBrowser.WebDashboard.Api { var sb = new StringBuilder(); + sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">"); sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">"); sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">"); - sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">"); //sb.Append("<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">"); // http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index ab32f9097..34739b26d 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.237</version> + <version>3.0.238</version> <title>MediaBrowser.Common.Internal</title> <authors>Luke</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.237" /> + <dependency id="MediaBrowser.Common" version="3.0.238" /> <dependency id="NLog" version="2.1.0" /> <dependency id="ServiceStack.Text" version="3.9.58" /> <dependency id="SimpleInjector" version="2.3.6" /> diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 54ddf0303..f93c862eb 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common</id> - <version>3.0.237</version> + <version>3.0.238</version> <title>MediaBrowser.Common</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 6237b923a..7a7216299 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Server.Core</id> - <version>3.0.237</version> + <version>3.0.238</version> <title>Media Browser.Server.Core</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains core components required to build plugins for Media Browser Server.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.237" /> + <dependency id="MediaBrowser.Common" version="3.0.238" /> </dependencies> </metadata> <files> |
