| 
					
				 | 
			
			
				@@ -1,3 +1,4 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#nullable enable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #pragma warning disable CS1591 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -11,7 +12,6 @@ using MediaBrowser.Controller.Providers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Drawing; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Dto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Entities; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Model.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.MediaInfo; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using Microsoft.Extensions.Logging; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -21,37 +21,33 @@ namespace MediaBrowser.Providers.MediaInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly IMediaEncoder _mediaEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly ILogger<VideoImageProvider> _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IFileSystem _fileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public VideoImageProvider(IMediaEncoder mediaEncoder, ILogger<VideoImageProvider> logger, IFileSystem fileSystem) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public VideoImageProvider(IMediaEncoder mediaEncoder, ILogger<VideoImageProvider> logger) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _mediaEncoder = mediaEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _fileSystem = fileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public string Name => "Screen Grabber"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // Make sure this comes after internet image providers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public int Order => 100; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public IEnumerable<ImageType> GetSupportedImages(BaseItem item) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return new List<ImageType> { ImageType.Primary }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new[] { ImageType.Primary }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public Task<DynamicImageResponse> GetImage(BaseItem item, ImageType type, CancellationToken cancellationToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var video = (Video)item; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // No support for this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (video.IsPlaceHolder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return Task.FromResult(new DynamicImageResponse { HasImage = false }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // No support for this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (video.VideoType == VideoType.Dvd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // No support for these 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (video.IsPlaceHolder || video.VideoType == VideoType.Dvd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Task.FromResult(new DynamicImageResponse { HasImage = false }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -59,18 +55,21 @@ namespace MediaBrowser.Providers.MediaInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Can't extract if we didn't find a video stream in the file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (!video.DefaultVideoStreamIndex.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _logger.LogInformation("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _logger.LogInformation("Skipping image extraction due to missing DefaultVideoStreamIndex for {Path}.", video.Path ?? string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Task.FromResult(new DynamicImageResponse { HasImage = false }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return GetVideoImage(video, cancellationToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public async Task<DynamicImageResponse> GetVideoImage(Video item, CancellationToken cancellationToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private async Task<DynamicImageResponse> GetVideoImage(Video item, CancellationToken cancellationToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var protocol = item.PathProtocol ?? MediaProtocol.File; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var inputPath = item.Path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            MediaSourceInfo mediaSource = new MediaSourceInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                VideoType = item.VideoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                IsoType = item.IsoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Protocol = item.PathProtocol ?? MediaProtocol.File, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var mediaStreams = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 item.GetMediaStreams(); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -80,41 +79,27 @@ namespace MediaBrowser.Providers.MediaInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     .Where(i => i.Type == MediaStreamType.EmbeddedImage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     .ToList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ?? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ?? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                imageStreams.FirstOrDefault(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             string extractedImagePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (imageStream != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                MediaSourceInfo mediaSource = new MediaSourceInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    VideoType = item.VideoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    IsoType = item.IsoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Protocol = item.PathProtocol.Value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, imageStream, imageStream.Index, cancellationToken).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (imageStreams.Count == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // If we know the duration, grab it from 10% into the video. Otherwise just 10 seconds in. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // Always use 10 seconds for dvd because our duration could be out of whack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var imageOffset = item.VideoType != VideoType.Dvd && item.RunTimeTicks.HasValue && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                   item.RunTimeTicks.Value > 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                      ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      ? TimeSpan.FromTicks(item.RunTimeTicks.Value / 10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                       : TimeSpan.FromSeconds(10); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var mediaSource = new MediaSourceInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    VideoType = item.VideoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    IsoType = item.IsoType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Protocol = item.PathProtocol.Value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                extractedImagePath = await _mediaEncoder.ExtractVideoImage(item.Path, item.Container, mediaSource, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var imageStream = imageStreams.Find(i => (i.Comment ?? string.Empty).Contains("front", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ?? imageStreams.Find(i => (i.Comment ?? string.Empty).Contains("cover", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ?? imageStreams[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                extractedImagePath = await _mediaEncoder.ExtractVideoImage(item.Path, item.Container, mediaSource, imageStream, imageStream.Index, cancellationToken).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return new DynamicImageResponse 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -126,6 +111,7 @@ namespace MediaBrowser.Providers.MediaInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public bool Supports(BaseItem item) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (item.IsShortcut) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -138,12 +124,7 @@ namespace MediaBrowser.Providers.MediaInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (item is Video video && !video.IsPlaceHolder && video.IsCompleteMedia) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return item is Video video && !video.IsPlaceHolder && video.IsCompleteMedia; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |