diff options
24 files changed, 333 insertions, 96 deletions
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index e8a09b2ae..e9911a12d 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -75,6 +75,7 @@ <Compile Include="ImageProcessor.cs" /> <Compile Include="ImageMagick\PercentPlayedDrawer.cs" /> <Compile Include="ImageMagick\PlayedIndicatorDrawer.cs" /> + <Compile Include="NullImageEncoder.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="ImageMagick\UnplayedCountIndicator.cs" /> </ItemGroup> @@ -99,6 +100,9 @@ <ItemGroup> <None Include="packages.config" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="GDI\empty.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/Emby.Drawing/GDI/GDIImageEncoder.cs b/Emby.Drawing/GDI/GDIImageEncoder.cs index 6d0998662..530613741 100644 --- a/Emby.Drawing/GDI/GDIImageEncoder.cs +++ b/Emby.Drawing/GDI/GDIImageEncoder.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Logging; using System; @@ -23,7 +22,20 @@ namespace Emby.Drawing.GDI _fileSystem = fileSystem; _logger = logger; - _logger.Info("GDI image processor initialized"); + LogInfo(); + } + + private void LogInfo() + { + _logger.Info("GDIImageEncoder starting"); + using (var stream = GetType().Assembly.GetManifestResourceStream(GetType().Namespace + ".empty.png")) + { + using (var img = Image.FromStream(stream)) + { + + } + } + _logger.Info("GDIImageEncoder started"); } public string[] SupportedInputFormats @@ -253,5 +265,15 @@ namespace Emby.Drawing.GDI { get { return "GDI"; } } + + public bool SupportsImageCollageCreation + { + get { return true; } + } + + public bool SupportsImageEncoding + { + get { return true; } + } } } diff --git a/Emby.Drawing/GDI/empty.png b/Emby.Drawing/GDI/empty.png Binary files differnew file mode 100644 index 000000000..42e2b375e --- /dev/null +++ b/Emby.Drawing/GDI/empty.png diff --git a/Emby.Drawing/IImageEncoder.cs b/Emby.Drawing/IImageEncoder.cs index 29261dbdb..4469075a6 100644 --- a/Emby.Drawing/IImageEncoder.cs +++ b/Emby.Drawing/IImageEncoder.cs @@ -17,12 +17,6 @@ namespace Emby.Drawing /// <value>The supported output formats.</value> ImageFormat[] SupportedOutputFormats { get; } /// <summary> - /// Gets the size of the image. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>ImageSize.</returns> - ImageSize GetImageSize(string path); - /// <summary> /// Crops the white space. /// </summary> /// <param name="inputPath">The input path.</param> @@ -49,5 +43,17 @@ namespace Emby.Drawing /// </summary> /// <value>The name.</value> string Name { get; } + + /// <summary> + /// Gets a value indicating whether [supports image collage creation]. + /// </summary> + /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value> + bool SupportsImageCollageCreation { get; } + + /// <summary> + /// Gets a value indicating whether [supports image encoding]. + /// </summary> + /// <value><c>true</c> if [supports image encoding]; otherwise, <c>false</c>.</value> + bool SupportsImageEncoding { get; } } } diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs index e73184974..ed0760ee3 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -9,7 +9,6 @@ using System; using System.IO; using System.Linq; using CommonIO; -using MediaBrowser.Common.IO; namespace Emby.Drawing.ImageMagick { @@ -27,7 +26,7 @@ namespace Emby.Drawing.ImageMagick _httpClient = httpClient; _fileSystem = fileSystem; - LogImageMagickVersion(); + LogVersion(); } public string[] SupportedInputFormats @@ -68,7 +67,7 @@ namespace Emby.Drawing.ImageMagick } } - private void LogImageMagickVersion() + private void LogVersion() { _logger.Info("ImageMagick version: " + Wand.VersionString); TestWebp(); @@ -88,9 +87,9 @@ namespace Emby.Drawing.ImageMagick wand.SaveImage(tmpPath); } } - catch (Exception ex) + catch { - _logger.ErrorException("Error loading webp: ", ex); + //_logger.ErrorException("Error loading webp: ", ex); _webpAvailable = false; } } @@ -255,5 +254,15 @@ namespace Emby.Drawing.ImageMagick throw new ObjectDisposedException(GetType().Name); } } + + public bool SupportsImageCollageCreation + { + get { return true; } + } + + public bool SupportsImageEncoding + { + get { return true; } + } } } diff --git a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs index e8161c179..a7e3a155d 100644 --- a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs +++ b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs @@ -354,14 +354,14 @@ namespace Emby.Drawing.ImageMagick private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height) { - var inputPaths = ImageHelpers.ProjectPaths(paths, 4); + var inputPaths = ImageHelpers.ProjectPaths(paths, 3); using (var wandImages = new MagickWand(inputPaths.ToArray())) { var wand = new MagickWand(width, height); wand.OpenImage("gradient:#111111-#111111"); using (var draw = new DrawingWand()) { - var iSlice = Convert.ToInt32(width * .225); + var iSlice = Convert.ToInt32(width * .3); int iTrans = Convert.ToInt32(height * .25); int iHeight = Convert.ToInt32(height * .63); var horizontalImagePadding = Convert.ToInt32(width * 0.02); diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 05c156e6a..9d7d1dbe9 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -110,6 +110,15 @@ namespace Emby.Drawing } } + + public bool SupportsImageCollageCreation + { + get + { + return _imageEncoder.SupportsImageCollageCreation; + } + } + private string ResizedImageCachePath { get @@ -170,6 +179,11 @@ namespace Emby.Drawing var originalImagePath = originalImage.Path; + if (!_imageEncoder.SupportsImageEncoding) + { + return originalImagePath; + } + if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) { // Just spit out the original file if all the options are default @@ -178,7 +192,7 @@ namespace Emby.Drawing var dateModified = originalImage.DateModified; - if (options.CropWhiteSpace) + if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); @@ -295,6 +309,11 @@ namespace Emby.Drawing _imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath); } + catch (NotImplementedException) + { + // No need to spam the log with an error message + return new Tuple<string, DateTime>(originalImagePath, dateModified); + } catch (Exception ex) { // We have to have a catch-all here because some of the .net image methods throw a plain old Exception diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs new file mode 100644 index 000000000..30ea36329 --- /dev/null +++ b/Emby.Drawing/NullImageEncoder.cs @@ -0,0 +1,64 @@ +using System; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Model.Drawing; + +namespace Emby.Drawing +{ + public class NullImageEncoder : IImageEncoder + { + public string[] SupportedInputFormats + { + get + { + return new[] + { + "png", + "jpeg", + "jpg" + }; + } + } + + public ImageFormat[] SupportedOutputFormats + { + get + { + return new[] { ImageFormat.Jpg, ImageFormat.Png }; + } + } + + public void CropWhiteSpace(string inputPath, string outputPath) + { + throw new NotImplementedException(); + } + + public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) + { + throw new NotImplementedException(); + } + + public void CreateImageCollage(ImageCollageOptions options) + { + throw new NotImplementedException(); + } + + public string Name + { + get { return "Null Image Encoder"; } + } + + public bool SupportsImageCollageCreation + { + get { return false; } + } + + public bool SupportsImageEncoding + { + get { return false; } + } + + public void Dispose() + { + } + } +} diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index dc88b2cbe..259789fd1 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -564,7 +564,14 @@ namespace MediaBrowser.Api.Images }).ToList() : new List<IImageEnhancer>(); - var format = GetOutputFormat(request, imageInfo, supportedImageEnhancers); + var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; + + if (request.CropWhitespace.HasValue) + { + cropwhitespace = request.CropWhitespace.Value; + } + + var format = GetOutputFormat(request, imageInfo, cropwhitespace, supportedImageEnhancers); var contentType = GetMimeType(format, imageInfo.Path); var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers)); @@ -585,6 +592,7 @@ namespace MediaBrowser.Api.Images return GetImageResult(item, request, imageInfo, + cropwhitespace, format, supportedImageEnhancers, contentType, @@ -597,6 +605,7 @@ namespace MediaBrowser.Api.Images private async Task<object> GetImageResult(IHasImages item, ImageRequest request, ItemImageInfo image, + bool cropwhitespace, ImageFormat format, List<IImageEnhancer> enhancers, string contentType, @@ -604,13 +613,6 @@ namespace MediaBrowser.Api.Images IDictionary<string, string> headers, bool isHeadRequest) { - var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; - - if (request.CropWhitespace.HasValue) - { - cropwhitespace = request.CropWhitespace.Value; - } - var options = new ImageProcessingOptions { CropWhiteSpace = cropwhitespace, @@ -644,7 +646,7 @@ namespace MediaBrowser.Api.Images }); } - private ImageFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, List<IImageEnhancer> enhancers) + private ImageFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List<IImageEnhancer> enhancers) { if (!string.IsNullOrWhiteSpace(request.Format)) { @@ -655,10 +657,37 @@ namespace MediaBrowser.Api.Images } } + var extension = Path.GetExtension(image.Path); + ImageFormat? inputFormat = null; + + if (string.Equals(extension, ".jpg", StringComparison.OrdinalIgnoreCase) || + string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase)) + { + inputFormat = ImageFormat.Jpg; + } + else if (string.Equals(extension, ".png", StringComparison.OrdinalIgnoreCase)) + { + inputFormat = ImageFormat.Png; + } + + var clientSupportedFormats = GetClientSupportedFormats(); + if (inputFormat.HasValue && clientSupportedFormats.Contains(inputFormat.Value) && enhancers.Count == 0) + { + if ((request.Quality ?? 100) == 100 && !request.Height.HasValue && !request.Width.HasValue && + !request.AddPlayedIndicator && !request.PercentPlayed.HasValue && !request.UnplayedCount.HasValue && string.IsNullOrWhiteSpace(request.BackgroundColor)) + { + // TODO: Allow this when specfying max width/height if the value is in range + if (!cropwhitespace && !request.MaxHeight.HasValue && !request.MaxWidth.HasValue) + { + return inputFormat.Value; + } + } + } + var serverFormats = _imageProcessor.GetSupportedImageOutputFormats(); - if (serverFormats.Contains(ImageFormat.Webp) && - GetClientSupportedFormats().Contains(ImageFormat.Webp)) + // Client doesn't care about format, so start with webp if supported + if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp)) { return ImageFormat.Webp; } @@ -668,10 +697,7 @@ namespace MediaBrowser.Api.Images return ImageFormat.Png; } - var extension = Path.GetExtension(image.Path); - - if (string.Equals(extension, ".jpg", StringComparison.OrdinalIgnoreCase) || - string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase)) + if (inputFormat.HasValue && inputFormat.Value == ImageFormat.Jpg) { return ImageFormat.Jpg; } @@ -682,7 +708,7 @@ namespace MediaBrowser.Api.Images private ImageFormat[] GetClientSupportedFormats() { - var supportsWebP = (Request.AcceptTypes ?? new string[] {}).Contains("image/webp", StringComparer.OrdinalIgnoreCase); + var supportsWebP = (Request.AcceptTypes ?? new string[] { }).Contains("image/webp", StringComparer.OrdinalIgnoreCase); var userAgent = Request.UserAgent ?? string.Empty; diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 76abfb743..decd19602 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Api.Library /// Gets or sets the path. /// </summary> /// <value>The path.</value> - public string Path { get; set; } + public string[] Paths { get; set; } } [Route("/Library/VirtualFolders", "DELETE")] @@ -207,11 +207,12 @@ namespace MediaBrowser.Api.Library throw new ArgumentException("There is already a media library with the name " + name + "."); } - if (!string.IsNullOrWhiteSpace(request.Path)) + if (request.Paths != null) { - if (!_fileSystem.DirectoryExists(request.Path)) + var invalidpath = request.Paths.FirstOrDefault(i => !_fileSystem.DirectoryExists(i)); + if (invalidpath != null) { - throw new DirectoryNotFoundException("The specified folder does not exist."); + throw new ArgumentException("The specified path does not exist: " + invalidpath + "."); } } @@ -231,9 +232,12 @@ namespace MediaBrowser.Api.Library } } - if (!string.IsNullOrWhiteSpace(request.Path)) + if (request.Paths != null) { - LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, _appPaths); + foreach (var path in request.Paths) + { + LibraryHelpers.AddMediaPath(_fileSystem, request.Name, path, _appPaths); + } } } finally diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index fea6b979d..e1e98857f 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -105,5 +105,11 @@ namespace MediaBrowser.Controller.Drawing /// </summary> /// <param name="options">The options.</param> Task CreateImageCollage(ImageCollageOptions options); + + /// <summary> + /// Gets a value indicating whether [supports image collage creation]. + /// </summary> + /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value> + bool SupportsImageCollageCreation { get; } } } diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 55184140e..3c2d9c82f 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -87,22 +87,26 @@ namespace MediaBrowser.Providers.Movies if (string.IsNullOrEmpty(tmdbId)) { movieInfo = await MovieDbProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false); - if (movieInfo == null) return item; - - tmdbId = movieInfo.id.ToString(_usCulture); + if (movieInfo != null) + { + tmdbId = movieInfo.id.ToString(_usCulture); - dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); - _jsonSerializer.SerializeToFile(movieInfo, dataFilePath); + dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); + _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _jsonSerializer.SerializeToFile(movieInfo, dataFilePath); + } } - await MovieDbProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false); + if (!string.IsNullOrWhiteSpace(tmdbId)) + { + await MovieDbProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false); - dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language); - movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath); + dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language); + movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath); - ProcessMainInfo(item, preferredCountryCode, movieInfo); - item.HasMetadata = true; + ProcessMainInfo(item, preferredCountryCode, movieInfo); + item.HasMetadata = true; + } return item; } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index c39c2ed68..a91714d32 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -16,9 +16,11 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Net; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Net; namespace MediaBrowser.Providers.Movies { @@ -116,7 +118,7 @@ namespace MediaBrowser.Providers.Movies public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken) where T : BaseItem, new() { - var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer, _libraryManager, _fileSystem); + var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer, _libraryManager, _fileSystem); return movieDb.GetMetadata(id, cancellationToken); } @@ -211,7 +213,7 @@ namespace MediaBrowser.Providers.Movies var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } @@ -309,25 +311,38 @@ namespace MediaBrowser.Providers.Movies var cacheMode = isTmdbId ? CacheMode.None : CacheMode.Unconditional; var cacheLength = TimeSpan.FromDays(3); - using (var json = await GetMovieDbResponse(new HttpRequestOptions + try { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = AcceptHeader, - CacheMode = cacheMode, - CacheLength = cacheLength + using (var json = await GetMovieDbResponse(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken, + AcceptHeader = AcceptHeader, + CacheMode = cacheMode, + CacheLength = cacheLength - }).ConfigureAwait(false)) + }).ConfigureAwait(false)) + { + mainResult = _jsonSerializer.DeserializeFromStream<CompleteMovieData>(json); + } + } + catch (HttpException ex) { - mainResult = _jsonSerializer.DeserializeFromStream<CompleteMovieData>(json); + // Return null so that callers know there is no metadata for this id + if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) + { + return null; + } + + throw; } cancellationToken.ThrowIfCancellationRequested(); // If the language preference isn't english, then have the overview fallback to english if it's blank if (mainResult != null && - string.IsNullOrEmpty(mainResult.overview) && - !string.IsNullOrEmpty(language) && + string.IsNullOrEmpty(mainResult.overview) && + !string.IsNullOrEmpty(language) && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) { _logger.Info("MovieDbProvider couldn't find meta for language " + language + ". Trying English..."); diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs index 5ff182844..9ea457284 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Server.Implementations.Photos; using MoreLinq; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; @@ -74,7 +75,27 @@ namespace MediaBrowser.Server.Implementations.Collections .DistinctBy(i => i.Id) .ToList(); - return Task.FromResult(GetFinalItems(items)); + return Task.FromResult(GetFinalItems(items, 2)); + } + + protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + { + var image = itemsWithImages + .Where(i => i.HasImage(ImageType.Primary) && i.GetImageInfo(ImageType.Primary, 0).IsLocalFile && Path.HasExtension(i.GetImagePath(ImageType.Primary))) + .Select(i => i.GetImagePath(ImageType.Primary)) + .FirstOrDefault(); + + if (string.IsNullOrWhiteSpace(image)) + { + return null; + } + + var ext = Path.GetExtension(image); + + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext); + File.Copy(image, outputPath); + + return outputPath; } } } diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs index 361514625..0b2c082a8 100644 --- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs +++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs @@ -265,6 +265,11 @@ namespace MediaBrowser.Server.Implementations.Devices return true; } + if (policy.IsAdministrator) + { + return true; + } + return ListHelper.ContainsIgnoreCase(policy.EnabledDevices, id); } } diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index c620cfdb5..e107ea9f1 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.IO // This is an arbitraty amount of time, but delay it because file system writes often trigger events long after the file was actually written to. // Seeing long delays in some situations, especially over the network, sometimes up to 45 seconds // But if we make this delay too high, we risk missing legitimate changes, such as user adding a new file, or hand-editing metadata - await Task.Delay(20000).ConfigureAwait(false); + await Task.Delay(25000).ConfigureAwait(false); string val; _tempIgnoredPaths.TryRemove(path, out val); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9f6e0ecce..2ac06cda8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -675,7 +675,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV Name = info.Name, EpisodeTitle = info.EpisodeTitle, ProgramId = info.Id, - HasImage = info.HasImage, ImagePath = info.ImagePath, ImageUrl = info.ImageUrl, OriginalAirDate = info.OriginalAirDate, diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index be2933be2..434578718 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -333,7 +333,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings IsRepeat = repeat, IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, ImageUrl = imageUrl, - HasImage = details.hasImageArtwork, IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index 15d76fb60..cac112b6c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -46,11 +46,6 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - protected virtual void DisposeInternal() - { - - } - protected abstract void CloseConnection(); } } diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs index b07b5b8c4..2402d3ec1 100644 --- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs @@ -92,11 +92,11 @@ namespace MediaBrowser.Server.Implementations.Photos string cacheKey, CancellationToken cancellationToken) { - var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png"); - FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); - var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false); + var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); + FileSystem.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension)); + string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false); - if (!imageCreated) + if (string.IsNullOrWhiteSpace(outputPath)) { return ItemUpdateType.None; } @@ -117,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Photos return parts.GetMD5().ToString("N"); } - protected Task<bool> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) + protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) { return CreateCollage(primaryItem, items, outputPath, 640, 360); } @@ -144,22 +144,22 @@ namespace MediaBrowser.Server.Implementations.Photos .Where(i => !string.IsNullOrWhiteSpace(i)); } - protected Task<bool> CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) + protected Task<string> CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) { return CreateCollage(primaryItem, items, outputPath, 400, 600); } - protected Task<bool> CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) + protected Task<string> CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) { return CreateCollage(primaryItem, items, outputPath, 600, 600); } - protected Task<bool> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height) + protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height) { return CreateCollage(primaryItem, items, outputPath, width, height); } - private Task<bool> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height) + private async Task<string> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height) { FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); @@ -173,11 +173,16 @@ namespace MediaBrowser.Server.Implementations.Photos if (options.InputPaths.Length == 0) { - return Task.FromResult(false); + return null; + } + + if (!ImageProcessor.SupportsImageCollageCreation) + { + return null; } - ImageProcessor.CreateImageCollage(options); - return Task.FromResult(true); + await ImageProcessor.CreateImageCollage(options).ConfigureAwait(false); + return outputPath; } public string Name @@ -185,17 +190,19 @@ namespace MediaBrowser.Server.Implementations.Photos get { return "Dynamic Image Provider"; } } - protected virtual async Task<bool> CreateImage(IHasImages item, + protected virtual async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, - string outputPath, + string outputPathWithoutExtension, ImageType imageType, int imageIndex) { if (itemsWithImages.Count == 0) { - return false; + return null; } + string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); + if (imageType == ImageType.Thumb) { return await CreateThumbCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); @@ -207,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.Photos { return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } - if (item is PhotoAlbum || item is Playlist) + if (item is Playlist) { return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } @@ -320,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.Photos var random = DateTime.Now.DayOfYear % MaxImageAgeDays; return items - .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5()) + .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5()) .Take(limit) .OrderBy(i => i.Name) .ToList(); diff --git a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs index 71f68e857..8b73d03d8 100644 --- a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs @@ -1,9 +1,9 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; @@ -20,9 +20,26 @@ namespace MediaBrowser.Server.Implementations.Photos protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item) { var photoAlbum = (PhotoAlbum)item; - var items = GetFinalItems(photoAlbum.Children.ToList()); + var items = GetFinalItems(photoAlbum.Children.ToList(), 1); return Task.FromResult(items); } + + protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, Model.Entities.ImageType imageType, int imageIndex) + { + var photoFile = itemsWithImages.Where(i => Path.HasExtension(i.Path)).Select(i => i.Path).FirstOrDefault(); + + if (string.IsNullOrWhiteSpace(photoFile)) + { + return null; + } + + var ext = Path.GetExtension(photoFile); + + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext); + File.Copy(photoFile, outputPath); + + return outputPath; + } } } diff --git a/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs index 9247edadb..de0b0e758 100644 --- a/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs @@ -10,6 +10,7 @@ using MediaBrowser.Server.Implementations.Photos; using MoreLinq; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; @@ -97,13 +98,15 @@ namespace MediaBrowser.Server.Implementations.UserViews return item is CollectionFolder; } - protected override async Task<bool> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex) + protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) { + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); + if (imageType == ImageType.Primary) { if (itemsWithImages.Count == 0) { - return false; + return null; } return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs index 8dfbe38f1..cdffadcd7 100644 --- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -11,6 +11,7 @@ using MediaBrowser.Server.Implementations.Photos; using MoreLinq; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; @@ -161,14 +162,16 @@ namespace MediaBrowser.Server.Implementations.UserViews return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty); } - protected override async Task<bool> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex) + protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) { + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); + var view = (UserView)item; if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) { if (itemsWithImages.Count == 0) { - return false; + return null; } return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 70e903114..aeafc1ede 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -577,11 +577,20 @@ namespace MediaBrowser.Server.Startup.Common } catch (Exception ex) { - Logger.ErrorException("Error loading ImageMagick. Will revert to GDI.", ex); + Logger.Error("Error loading ImageMagick. Will revert to GDI."); } } - return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI")); + try + { + return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI")); + } + catch (Exception ex) + { + Logger.Error("Error loading GDI. Will revert to NullImageEncoder."); + } + + return new NullImageEncoder(); } protected override INetworkManager CreateNetworkManager(ILogger logger) |
