mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 10:37:22 -04:00 
			
		
		
		
	support null image encoder
This commit is contained in:
		
							parent
							
								
									2890c71af9
								
							
						
					
					
						commit
						c80e1df1ca
					
				| @ -75,6 +75,7 @@ | |||||||
|     <Compile Include="ImageProcessor.cs" /> |     <Compile Include="ImageProcessor.cs" /> | ||||||
|     <Compile Include="ImageMagick\PercentPlayedDrawer.cs" /> |     <Compile Include="ImageMagick\PercentPlayedDrawer.cs" /> | ||||||
|     <Compile Include="ImageMagick\PlayedIndicatorDrawer.cs" /> |     <Compile Include="ImageMagick\PlayedIndicatorDrawer.cs" /> | ||||||
|  |     <Compile Include="NullImageEncoder.cs" /> | ||||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> |     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||||
|     <Compile Include="ImageMagick\UnplayedCountIndicator.cs" /> |     <Compile Include="ImageMagick\UnplayedCountIndicator.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| @ -99,6 +100,9 @@ | |||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <None Include="packages.config" /> |     <None Include="packages.config" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <EmbeddedResource Include="GDI\empty.png" /> | ||||||
|  |   </ItemGroup> | ||||||
|   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||||
|   <!-- To modify your build process, add your task inside one of the targets below and uncomment it.  |   <!-- 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. |        Other similar extension points exist, see Microsoft.Common.targets. | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| using MediaBrowser.Common.IO; | using MediaBrowser.Controller.Drawing; | ||||||
| using MediaBrowser.Controller.Drawing; |  | ||||||
| using MediaBrowser.Model.Drawing; | using MediaBrowser.Model.Drawing; | ||||||
| using MediaBrowser.Model.Logging; | using MediaBrowser.Model.Logging; | ||||||
| using System; | using System; | ||||||
| @ -23,7 +22,20 @@ namespace Emby.Drawing.GDI | |||||||
|             _fileSystem = fileSystem; |             _fileSystem = fileSystem; | ||||||
|             _logger = logger; |             _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 |         public string[] SupportedInputFormats | ||||||
| @ -253,5 +265,15 @@ namespace Emby.Drawing.GDI | |||||||
|         { |         { | ||||||
|             get { return "GDI"; } |             get { return "GDI"; } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public bool SupportsImageCollageCreation | ||||||
|  |         { | ||||||
|  |             get { return true; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool SupportsImageEncoding | ||||||
|  |         { | ||||||
|  |             get { return true; } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								Emby.Drawing/GDI/empty.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Emby.Drawing/GDI/empty.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 158 B | 
| @ -17,12 +17,6 @@ namespace Emby.Drawing | |||||||
|         /// <value>The supported output formats.</value> |         /// <value>The supported output formats.</value> | ||||||
|         ImageFormat[] SupportedOutputFormats { get; } |         ImageFormat[] SupportedOutputFormats { get; } | ||||||
|         /// <summary> |         /// <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. |         /// Crops the white space. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="inputPath">The input path.</param> |         /// <param name="inputPath">The input path.</param> | ||||||
| @ -49,5 +43,17 @@ namespace Emby.Drawing | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <value>The name.</value> |         /// <value>The name.</value> | ||||||
|         string Name { get; } |         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; } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,7 +9,6 @@ using System; | |||||||
| using System.IO; | using System.IO; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using CommonIO; | using CommonIO; | ||||||
| using MediaBrowser.Common.IO; |  | ||||||
| 
 | 
 | ||||||
| namespace Emby.Drawing.ImageMagick | namespace Emby.Drawing.ImageMagick | ||||||
| { | { | ||||||
| @ -27,7 +26,7 @@ namespace Emby.Drawing.ImageMagick | |||||||
|             _httpClient = httpClient; |             _httpClient = httpClient; | ||||||
|             _fileSystem = fileSystem; |             _fileSystem = fileSystem; | ||||||
| 
 | 
 | ||||||
|             LogImageMagickVersion(); |             LogVersion(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public string[] SupportedInputFormats |         public string[] SupportedInputFormats | ||||||
| @ -68,7 +67,7 @@ namespace Emby.Drawing.ImageMagick | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void LogImageMagickVersion() |         private void LogVersion() | ||||||
|         { |         { | ||||||
|             _logger.Info("ImageMagick version: " + Wand.VersionString); |             _logger.Info("ImageMagick version: " + Wand.VersionString); | ||||||
|             TestWebp(); |             TestWebp(); | ||||||
| @ -88,9 +87,9 @@ namespace Emby.Drawing.ImageMagick | |||||||
|                     wand.SaveImage(tmpPath); |                     wand.SaveImage(tmpPath); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             catch (Exception ex) |             catch  | ||||||
|             { |             { | ||||||
|                 _logger.ErrorException("Error loading webp: ", ex); |                 //_logger.ErrorException("Error loading webp: ", ex); | ||||||
|                 _webpAvailable = false; |                 _webpAvailable = false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -255,5 +254,15 @@ namespace Emby.Drawing.ImageMagick | |||||||
|                 throw new ObjectDisposedException(GetType().Name); |                 throw new ObjectDisposedException(GetType().Name); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public bool SupportsImageCollageCreation | ||||||
|  |         { | ||||||
|  |             get { return true; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool SupportsImageEncoding | ||||||
|  |         { | ||||||
|  |             get { return true; } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -354,14 +354,14 @@ namespace Emby.Drawing.ImageMagick | |||||||
| 
 | 
 | ||||||
|         private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height) |         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())) |             using (var wandImages = new MagickWand(inputPaths.ToArray())) | ||||||
|             { |             { | ||||||
|                 var wand = new MagickWand(width, height); |                 var wand = new MagickWand(width, height); | ||||||
|                 wand.OpenImage("gradient:#111111-#111111"); |                 wand.OpenImage("gradient:#111111-#111111"); | ||||||
|                 using (var draw = new DrawingWand()) |                 using (var draw = new DrawingWand()) | ||||||
|                 { |                 { | ||||||
|                     var iSlice = Convert.ToInt32(width * .225); |                     var iSlice = Convert.ToInt32(width * .3); | ||||||
|                     int iTrans = Convert.ToInt32(height * .25); |                     int iTrans = Convert.ToInt32(height * .25); | ||||||
|                     int iHeight = Convert.ToInt32(height * .63); |                     int iHeight = Convert.ToInt32(height * .63); | ||||||
|                     var horizontalImagePadding = Convert.ToInt32(width * 0.02); |                     var horizontalImagePadding = Convert.ToInt32(width * 0.02); | ||||||
|  | |||||||
| @ -110,6 +110,15 @@ namespace Emby.Drawing | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |         public bool SupportsImageCollageCreation | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 return _imageEncoder.SupportsImageCollageCreation; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         private string ResizedImageCachePath |         private string ResizedImageCachePath | ||||||
|         { |         { | ||||||
|             get |             get | ||||||
| @ -170,6 +179,11 @@ namespace Emby.Drawing | |||||||
| 
 | 
 | ||||||
|             var originalImagePath = originalImage.Path; |             var originalImagePath = originalImage.Path; | ||||||
| 
 | 
 | ||||||
|  |             if (!_imageEncoder.SupportsImageEncoding) | ||||||
|  |             { | ||||||
|  |                 return originalImagePath; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) |             if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) | ||||||
|             { |             { | ||||||
|                 // Just spit out the original file if all the options are default |                 // Just spit out the original file if all the options are default | ||||||
| @ -178,7 +192,7 @@ namespace Emby.Drawing | |||||||
| 
 | 
 | ||||||
|             var dateModified = originalImage.DateModified; |             var dateModified = originalImage.DateModified; | ||||||
| 
 | 
 | ||||||
|             if (options.CropWhiteSpace) |             if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding) | ||||||
|             { |             { | ||||||
|                 var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); |                 var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); | ||||||
| 
 | 
 | ||||||
| @ -295,6 +309,11 @@ namespace Emby.Drawing | |||||||
| 
 | 
 | ||||||
|                 _imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath); |                 _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) |             catch (Exception ex) | ||||||
|             { |             { | ||||||
|                 // We have to have a catch-all here because some of the .net image methods throw a plain old Exception |                 // We have to have a catch-all here because some of the .net image methods throw a plain old Exception | ||||||
|  | |||||||
							
								
								
									
										64
									
								
								Emby.Drawing/NullImageEncoder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Emby.Drawing/NullImageEncoder.cs
									
									
									
									
									
										Normal file
									
								
							| @ -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() | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -564,7 +564,14 @@ namespace MediaBrowser.Api.Images | |||||||
| 
 | 
 | ||||||
|             }).ToList() : new List<IImageEnhancer>(); |             }).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 contentType = GetMimeType(format, imageInfo.Path); | ||||||
| 
 | 
 | ||||||
|             var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers)); |             var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers)); | ||||||
| @ -585,6 +592,7 @@ namespace MediaBrowser.Api.Images | |||||||
|             return GetImageResult(item, |             return GetImageResult(item, | ||||||
|                 request, |                 request, | ||||||
|                 imageInfo, |                 imageInfo, | ||||||
|  |                 cropwhitespace, | ||||||
|                 format, |                 format, | ||||||
|                 supportedImageEnhancers, |                 supportedImageEnhancers, | ||||||
|                 contentType, |                 contentType, | ||||||
| @ -597,6 +605,7 @@ namespace MediaBrowser.Api.Images | |||||||
|         private async Task<object> GetImageResult(IHasImages item, |         private async Task<object> GetImageResult(IHasImages item, | ||||||
|             ImageRequest request, |             ImageRequest request, | ||||||
|             ItemImageInfo image, |             ItemImageInfo image, | ||||||
|  |             bool cropwhitespace, | ||||||
|             ImageFormat format, |             ImageFormat format, | ||||||
|             List<IImageEnhancer> enhancers, |             List<IImageEnhancer> enhancers, | ||||||
|             string contentType, |             string contentType, | ||||||
| @ -604,13 +613,6 @@ namespace MediaBrowser.Api.Images | |||||||
|             IDictionary<string, string> headers, |             IDictionary<string, string> headers, | ||||||
|             bool isHeadRequest) |             bool isHeadRequest) | ||||||
|         { |         { | ||||||
|             var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; |  | ||||||
| 
 |  | ||||||
|             if (request.CropWhitespace.HasValue) |  | ||||||
|             { |  | ||||||
|                 cropwhitespace = request.CropWhitespace.Value; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var options = new ImageProcessingOptions |             var options = new ImageProcessingOptions | ||||||
|             { |             { | ||||||
|                 CropWhiteSpace = cropwhitespace, |                 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)) |             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(); |             var serverFormats = _imageProcessor.GetSupportedImageOutputFormats(); | ||||||
| 
 | 
 | ||||||
|             if (serverFormats.Contains(ImageFormat.Webp) && |             // Client doesn't care about format, so start with webp if supported | ||||||
|                 GetClientSupportedFormats().Contains(ImageFormat.Webp)) |             if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp)) | ||||||
|             { |             { | ||||||
|                 return ImageFormat.Webp; |                 return ImageFormat.Webp; | ||||||
|             } |             } | ||||||
| @ -668,10 +697,7 @@ namespace MediaBrowser.Api.Images | |||||||
|                 return ImageFormat.Png; |                 return ImageFormat.Png; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var extension = Path.GetExtension(image.Path); |             if (inputFormat.HasValue && inputFormat.Value == ImageFormat.Jpg) | ||||||
| 
 |  | ||||||
|             if (string.Equals(extension, ".jpg", StringComparison.OrdinalIgnoreCase) || |  | ||||||
|                 string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase)) |  | ||||||
|             { |             { | ||||||
|                 return ImageFormat.Jpg; |                 return ImageFormat.Jpg; | ||||||
|             } |             } | ||||||
| @ -682,7 +708,7 @@ namespace MediaBrowser.Api.Images | |||||||
| 
 | 
 | ||||||
|         private ImageFormat[] GetClientSupportedFormats() |         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; |             var userAgent = Request.UserAgent ?? string.Empty; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ namespace MediaBrowser.Api.Library | |||||||
|         /// Gets or sets the path. |         /// Gets or sets the path. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <value>The path.</value> |         /// <value>The path.</value> | ||||||
|         public string Path { get; set; } |         public string[] Paths { get; set; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     [Route("/Library/VirtualFolders", "DELETE")] |     [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 + "."); |                 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 |             finally | ||||||
|  | |||||||
| @ -105,5 +105,11 @@ namespace MediaBrowser.Controller.Drawing | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="options">The options.</param> |         /// <param name="options">The options.</param> | ||||||
|         Task CreateImageCollage(ImageCollageOptions options); |         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; } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -87,22 +87,26 @@ namespace MediaBrowser.Providers.Movies | |||||||
|             if (string.IsNullOrEmpty(tmdbId)) |             if (string.IsNullOrEmpty(tmdbId)) | ||||||
|             { |             { | ||||||
|                 movieInfo = await MovieDbProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false); |                 movieInfo = await MovieDbProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false); | ||||||
|                 if (movieInfo == null) return item; |                 if (movieInfo != null) | ||||||
|  |                 { | ||||||
|  |                     tmdbId = movieInfo.id.ToString(_usCulture); | ||||||
| 
 | 
 | ||||||
|                 tmdbId = movieInfo.id.ToString(_usCulture); |                     dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); | ||||||
| 
 |                     _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); | ||||||
|                 dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); |                     _jsonSerializer.SerializeToFile(movieInfo, dataFilePath); | ||||||
| 				_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); |                 dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language); | ||||||
|             movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath); |                 movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath); | ||||||
| 
 | 
 | ||||||
|             ProcessMainInfo(item, preferredCountryCode, movieInfo); |                 ProcessMainInfo(item, preferredCountryCode, movieInfo); | ||||||
|             item.HasMetadata = true; |                 item.HasMetadata = true; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             return item; |             return item; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -16,9 +16,11 @@ using System; | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Globalization; | using System.Globalization; | ||||||
| using System.IO; | using System.IO; | ||||||
|  | using System.Net; | ||||||
| using System.Threading; | using System.Threading; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using CommonIO; | using CommonIO; | ||||||
|  | using MediaBrowser.Model.Net; | ||||||
| 
 | 
 | ||||||
| namespace MediaBrowser.Providers.Movies | namespace MediaBrowser.Providers.Movies | ||||||
| { | { | ||||||
| @ -116,7 +118,7 @@ namespace MediaBrowser.Providers.Movies | |||||||
|         public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken) |         public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken) | ||||||
|             where T : BaseItem, new() |             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); |             return movieDb.GetMetadata(id, cancellationToken); | ||||||
|         } |         } | ||||||
| @ -211,7 +213,7 @@ namespace MediaBrowser.Providers.Movies | |||||||
| 
 | 
 | ||||||
|             var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); |             var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); | ||||||
| 
 | 
 | ||||||
| 			_fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); |             _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); | ||||||
| 
 | 
 | ||||||
|             _jsonSerializer.SerializeToFile(mainResult, dataFilePath); |             _jsonSerializer.SerializeToFile(mainResult, dataFilePath); | ||||||
|         } |         } | ||||||
| @ -309,25 +311,38 @@ namespace MediaBrowser.Providers.Movies | |||||||
|             var cacheMode = isTmdbId ? CacheMode.None : CacheMode.Unconditional; |             var cacheMode = isTmdbId ? CacheMode.None : CacheMode.Unconditional; | ||||||
|             var cacheLength = TimeSpan.FromDays(3); |             var cacheLength = TimeSpan.FromDays(3); | ||||||
| 
 | 
 | ||||||
|             using (var json = await GetMovieDbResponse(new HttpRequestOptions |             try | ||||||
|             { |             { | ||||||
|                 Url = url, |                 using (var json = await GetMovieDbResponse(new HttpRequestOptions | ||||||
|                 CancellationToken = cancellationToken, |                 { | ||||||
|                 AcceptHeader = AcceptHeader, |                     Url = url, | ||||||
|                 CacheMode = cacheMode, |                     CancellationToken = cancellationToken, | ||||||
|                 CacheLength = cacheLength |                     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(); |             cancellationToken.ThrowIfCancellationRequested(); | ||||||
| 
 | 
 | ||||||
|             // If the language preference isn't english, then have the overview fallback to english if it's blank |             // If the language preference isn't english, then have the overview fallback to english if it's blank | ||||||
|             if (mainResult != null && |             if (mainResult != null && | ||||||
|                 string.IsNullOrEmpty(mainResult.overview) &&  |                 string.IsNullOrEmpty(mainResult.overview) && | ||||||
|                 !string.IsNullOrEmpty(language) &&  |                 !string.IsNullOrEmpty(language) && | ||||||
|                 !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) |                 !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) | ||||||
|             { |             { | ||||||
|                 _logger.Info("MovieDbProvider couldn't find meta for language " + language + ". Trying English..."); |                 _logger.Info("MovieDbProvider couldn't find meta for language " + language + ". Trying English..."); | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ using MediaBrowser.Model.Entities; | |||||||
| using MediaBrowser.Server.Implementations.Photos; | using MediaBrowser.Server.Implementations.Photos; | ||||||
| using MoreLinq; | using MoreLinq; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using CommonIO; | using CommonIO; | ||||||
| @ -74,7 +75,27 @@ namespace MediaBrowser.Server.Implementations.Collections | |||||||
|                 .DistinctBy(i => i.Id) |                 .DistinctBy(i => i.Id) | ||||||
|                 .ToList(); |                 .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; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -265,6 +265,11 @@ namespace MediaBrowser.Server.Implementations.Devices | |||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             if (policy.IsAdministrator) | ||||||
|  |             { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             return ListHelper.ContainsIgnoreCase(policy.EnabledDevices, id); |             return ListHelper.ContainsIgnoreCase(policy.EnabledDevices, id); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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. |             // 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 |             // 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 |             // 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; |             string val; | ||||||
|             _tempIgnoredPaths.TryRemove(path, out val); |             _tempIgnoredPaths.TryRemove(path, out val); | ||||||
|  | |||||||
| @ -675,7 +675,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV | |||||||
|                     Name = info.Name, |                     Name = info.Name, | ||||||
|                     EpisodeTitle = info.EpisodeTitle, |                     EpisodeTitle = info.EpisodeTitle, | ||||||
|                     ProgramId = info.Id, |                     ProgramId = info.Id, | ||||||
|                     HasImage = info.HasImage, |  | ||||||
|                     ImagePath = info.ImagePath, |                     ImagePath = info.ImagePath, | ||||||
|                     ImageUrl = info.ImageUrl, |                     ImageUrl = info.ImageUrl, | ||||||
|                     OriginalAirDate = info.OriginalAirDate, |                     OriginalAirDate = info.OriginalAirDate, | ||||||
|  | |||||||
| @ -333,7 +333,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings | |||||||
|                 IsRepeat = repeat, |                 IsRepeat = repeat, | ||||||
|                 IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, |                 IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, | ||||||
|                 ImageUrl = imageUrl, |                 ImageUrl = imageUrl, | ||||||
|                 HasImage = details.hasImageArtwork, |  | ||||||
|                 IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), |                 IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), | ||||||
|                 IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, |                 IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, | ||||||
|                 IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, |                 IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, | ||||||
|  | |||||||
| @ -46,11 +46,6 @@ namespace MediaBrowser.Server.Implementations.Persistence | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected virtual void DisposeInternal() |  | ||||||
|         { |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         protected abstract void CloseConnection(); |         protected abstract void CloseConnection(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -92,11 +92,11 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|             string cacheKey, |             string cacheKey, | ||||||
|             CancellationToken cancellationToken) |             CancellationToken cancellationToken) | ||||||
|         { |         { | ||||||
|             var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png"); |             var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); | ||||||
|             FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); |             FileSystem.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension)); | ||||||
|             var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false); |             string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false); | ||||||
| 
 | 
 | ||||||
|             if (!imageCreated) |             if (string.IsNullOrWhiteSpace(outputPath)) | ||||||
|             { |             { | ||||||
|                 return ItemUpdateType.None; |                 return ItemUpdateType.None; | ||||||
|             } |             } | ||||||
| @ -117,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|             return parts.GetMD5().ToString("N"); |             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); |             return CreateCollage(primaryItem, items, outputPath, 640, 360); | ||||||
|         } |         } | ||||||
| @ -144,22 +144,22 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|                 .Where(i => !string.IsNullOrWhiteSpace(i)); |                 .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); |             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); |             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); |             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)); |             FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); | ||||||
| 
 | 
 | ||||||
| @ -173,11 +173,16 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
| 
 | 
 | ||||||
|             if (options.InputPaths.Length == 0) |             if (options.InputPaths.Length == 0) | ||||||
|             { |             { | ||||||
|                 return Task.FromResult(false); |                 return null; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ImageProcessor.CreateImageCollage(options); |             if (!ImageProcessor.SupportsImageCollageCreation) | ||||||
|             return Task.FromResult(true); |             { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             await ImageProcessor.CreateImageCollage(options).ConfigureAwait(false); | ||||||
|  |             return outputPath; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public string Name |         public string Name | ||||||
| @ -185,17 +190,19 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|             get { return "Dynamic Image Provider"; } |             get { return "Dynamic Image Provider"; } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected virtual async Task<bool> CreateImage(IHasImages item, |         protected virtual async Task<string> CreateImage(IHasImages item, | ||||||
|             List<BaseItem> itemsWithImages, |             List<BaseItem> itemsWithImages, | ||||||
|             string outputPath, |             string outputPathWithoutExtension, | ||||||
|             ImageType imageType, |             ImageType imageType, | ||||||
|             int imageIndex) |             int imageIndex) | ||||||
|         { |         { | ||||||
|             if (itemsWithImages.Count == 0) |             if (itemsWithImages.Count == 0) | ||||||
|             { |             { | ||||||
|                 return false; |                 return null; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); | ||||||
|  | 
 | ||||||
|             if (imageType == ImageType.Thumb) |             if (imageType == ImageType.Thumb) | ||||||
|             { |             { | ||||||
|                 return await CreateThumbCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); |                 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); |                     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); |                     return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); | ||||||
|                 } |                 } | ||||||
| @ -320,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|             var random = DateTime.Now.DayOfYear % MaxImageAgeDays; |             var random = DateTime.Now.DayOfYear % MaxImageAgeDays; | ||||||
| 
 | 
 | ||||||
|             return items |             return items | ||||||
|                 .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5()) |                 .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5()) | ||||||
|                 .Take(limit) |                 .Take(limit) | ||||||
|                 .OrderBy(i => i.Name) |                 .OrderBy(i => i.Name) | ||||||
|                 .ToList(); |                 .ToList(); | ||||||
|  | |||||||
| @ -1,9 +1,9 @@ | |||||||
| using MediaBrowser.Common.Configuration; | using MediaBrowser.Common.Configuration; | ||||||
| using MediaBrowser.Common.IO; |  | ||||||
| using MediaBrowser.Controller.Drawing; | using MediaBrowser.Controller.Drawing; | ||||||
| using MediaBrowser.Controller.Entities; | using MediaBrowser.Controller.Entities; | ||||||
| using MediaBrowser.Controller.Providers; | using MediaBrowser.Controller.Providers; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using CommonIO; | using CommonIO; | ||||||
| @ -20,9 +20,26 @@ namespace MediaBrowser.Server.Implementations.Photos | |||||||
|         protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item) |         protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item) | ||||||
|         { |         { | ||||||
|             var photoAlbum = (PhotoAlbum)item; |             var photoAlbum = (PhotoAlbum)item; | ||||||
|             var items = GetFinalItems(photoAlbum.Children.ToList()); |             var items = GetFinalItems(photoAlbum.Children.ToList(), 1); | ||||||
| 
 | 
 | ||||||
|             return Task.FromResult(items); |             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; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ using MediaBrowser.Server.Implementations.Photos; | |||||||
| using MoreLinq; | using MoreLinq; | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using CommonIO; | using CommonIO; | ||||||
| @ -97,13 +98,15 @@ namespace MediaBrowser.Server.Implementations.UserViews | |||||||
|             return item is CollectionFolder; |             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 (imageType == ImageType.Primary) | ||||||
|             { |             { | ||||||
|                 if (itemsWithImages.Count == 0) |                 if (itemsWithImages.Count == 0) | ||||||
|                 { |                 { | ||||||
|                     return false; |                     return null; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); |                 return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ using MediaBrowser.Server.Implementations.Photos; | |||||||
| using MoreLinq; | using MoreLinq; | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using CommonIO; | using CommonIO; | ||||||
| @ -161,14 +162,16 @@ namespace MediaBrowser.Server.Implementations.UserViews | |||||||
|             return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty); |             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; |             var view = (UserView)item; | ||||||
|             if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) |             if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) | ||||||
|             { |             { | ||||||
|                 if (itemsWithImages.Count == 0) |                 if (itemsWithImages.Count == 0) | ||||||
|                 { |                 { | ||||||
|                     return false; |                     return null; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); |                 return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); | ||||||
|  | |||||||
| @ -577,11 +577,20 @@ namespace MediaBrowser.Server.Startup.Common | |||||||
|                 } |                 } | ||||||
|                 catch (Exception ex) |                 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) |         protected override INetworkManager CreateNetworkManager(ILogger logger) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user