/// <summary> /// Extracts the image. /// </summary> /// <param name="video">The video.</param> /// <param name="path">The path.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task ExtractImageInternal(Video video, string path, CancellationToken cancellationToken) { var isoMount = await MountIsoIfNeeded(video, cancellationToken).ConfigureAwait(false); try { // 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 = video.VideoType != VideoType.Dvd && video.RunTimeTicks.HasValue && video.RunTimeTicks.Value > 0 ? TimeSpan.FromTicks(Convert.ToInt64(video.RunTimeTicks.Value * .1)) : TimeSpan.FromSeconds(10); InputType type; var inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type); await _mediaEncoder.ExtractImage(inputPath, type, video.Video3DFormat, imageOffset, path, cancellationToken).ConfigureAwait(false); video.PrimaryImagePath = path; } finally { if (isoMount != null) { isoMount.Dispose(); } } }
public async Task <DynamicImageResponse> GetVideoImage(Video item, CancellationToken cancellationToken) { var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false); try { // 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.FromSeconds(10); InputType type; var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, item.LocationType == LocationType.Remote, item.VideoType, item.IsoType, isoMount, item.PlayableStreamFileNames, out type); var stream = await _mediaEncoder.ExtractImage(inputPath, type, false, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); return(new DynamicImageResponse { Format = ImageFormat.Jpg, HasImage = true, Stream = stream }); } finally { if (isoMount != null) { isoMount.Dispose(); } } }
/// <summary> /// Creates the images for song. /// </summary> /// <param name="item">The item.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.InvalidOperationException">Can't extract an image unless the audio file has an embedded image.</exception> private async Task CreateImagesForSong(Audio item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var album = item.Parent as MusicAlbum; var filename = item.Album ?? string.Empty; filename += item.Artists.FirstOrDefault() ?? string.Empty; filename += album == null?item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks; var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg"); if (!File.Exists(path)) { var semaphore = GetLock(path); // Acquire a lock await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); // Check again if (!File.Exists(path)) { try { var parentPath = Path.GetDirectoryName(path); if (!Directory.Exists(parentPath)) { Directory.CreateDirectory(parentPath); } await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.AudioFile, null, null, path, cancellationToken).ConfigureAwait(false); } finally { semaphore.Release(); } } else { semaphore.Release(); } } // Image is already in the cache item.PrimaryImagePath = path; }
public async Task <DynamicImageResponse> GetImage(Audio item, CancellationToken cancellationToken) { var path = GetAudioImagePath(item); if (!File.Exists(path)) { var semaphore = GetLock(path); // Acquire a lock await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { // Check again in case it was saved while waiting for the lock if (!File.Exists(path)) { Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var stream = await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.File, true, null, null, cancellationToken).ConfigureAwait(false)) { using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } } } } finally { semaphore.Release(); } } return(new DynamicImageResponse { HasImage = true, Path = path }); }
public async Task <bool> RefreshChapterImages(ChapterImageRefreshOptions options, CancellationToken cancellationToken) { var extractImages = options.ExtractImages; var video = options.Video; var chapters = options.Chapters; var saveChapters = options.SaveChapters; if (!IsEligibleForChapterImageExtraction(video)) { extractImages = false; } var success = true; var changesMade = false; var runtimeTicks = video.RunTimeTicks ?? 0; var currentImages = GetSavedChapterImages(video); foreach (var chapter in chapters) { if (chapter.StartPositionTicks >= runtimeTicks) { _logger.Info("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name); break; } var path = GetChapterImagePath(video, chapter.StartPositionTicks); if (!currentImages.Contains(path, StringComparer.OrdinalIgnoreCase)) { if (extractImages) { if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso) { continue; } if (video.VideoType == VideoType.BluRay) { // Can only extract reliably on single file blurays if (video.PlayableStreamFileNames == null || video.PlayableStreamFileNames.Count != 1) { continue; } } // Add some time for the first chapter to make sure we don't end up with a black image var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); InputType type; var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, false, video.VideoType, video.IsoType, null, video.PlayableStreamFileNames, out type); try { Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var stream = await _encoder.ExtractImage(inputPath, type, false, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false)) { using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } } chapter.ImagePath = path; changesMade = true; } catch { success = false; break; } } else if (!string.IsNullOrEmpty(chapter.ImagePath)) { chapter.ImagePath = null; changesMade = true; } } else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) { chapter.ImagePath = path; changesMade = true; } } if (saveChapters && changesMade) { await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false); } DeleteDeadImages(currentImages, chapters); return(success); }
/// <summary> /// Extracts the chapter images. /// </summary> /// <param name="video">The video.</param> /// <param name="chapters">The chapters.</param> /// <param name="extractImages">if set to <c>true</c> [extract images].</param> /// <param name="saveChapters">if set to <c>true</c> [save chapters].</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> public async Task <bool> PopulateChapterImages(Video video, List <ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken) { // Can't extract images if there are no video streams if (video.MediaStreams == null || video.MediaStreams.All(m => m.Type != MediaStreamType.Video)) { return(true); } var success = true; var changesMade = false; var runtimeTicks = video.RunTimeTicks ?? 0; foreach (var chapter in chapters) { if (chapter.StartPositionTicks >= runtimeTicks) { _logger.Info("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name); break; } var filename = video.Path + "_" + video.DateModified.Ticks + "_" + chapter.StartPositionTicks; var path = VideoImageCache.GetResourcePath(filename, ".jpg"); if (!File.Exists(path)) { if (extractImages) { if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso) { continue; } if (video.VideoType == VideoType.BluRay) { // Can only extract reliably on single file blurays if (video.PlayableStreamFileNames == null || video.PlayableStreamFileNames.Count != 1) { continue; } } // Add some time for the first chapter to make sure we don't end up with a black image var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); InputType type; var inputPath = MediaEncoderHelpers.GetInputArgument(video, null, out type); try { var parentPath = Path.GetDirectoryName(path); if (!Directory.Exists(parentPath)) { Directory.CreateDirectory(parentPath); } await _encoder.ExtractImage(inputPath, type, video.Video3DFormat, time, path, cancellationToken).ConfigureAwait(false); chapter.ImagePath = path; changesMade = true; } catch { success = false; break; } } } else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) { chapter.ImagePath = path; changesMade = true; } } if (saveChapters && changesMade) { await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false); } return(success); }