< Summary - Jellyfin

Information
Class: Jellyfin.MediaEncoding.Hls.ScheduledTasks.KeyframeExtractionScheduledTask
Assembly: Jellyfin.MediaEncoding.Hls
File(s): /srv/git/jellyfin/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs
Line coverage
11%
Covered lines: 6
Uncovered lines: 46
Coverable lines: 52
Total lines: 110
Line coverage: 11.5%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 3/5/2026 - 12:13:57 AM Line coverage: 11.7% (6/51) Branch coverage: 0% (0/10) Total lines: 1096/9/2026 - 12:16:23 AM Line coverage: 11.5% (6/52) Branch coverage: 0% (0/10) Total lines: 110 3/5/2026 - 12:13:57 AM Line coverage: 11.7% (6/51) Branch coverage: 0% (0/10) Total lines: 1096/9/2026 - 12:16:23 AM Line coverage: 11.5% (6/52) Branch coverage: 0% (0/10) Total lines: 110

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
.ctor(...)100%11100%
get_Name()100%210%
get_Key()100%210%
get_Description()100%210%
get_Category()100%210%
ExecuteAsync(...)0%110100%
GetDefaultTriggers()100%11100%

File(s)

/srv/git/jellyfin/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using System.Linq;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using Jellyfin.Data.Enums;
 8using Jellyfin.MediaEncoding.Hls.Extractors;
 9using MediaBrowser.Controller.Dto;
 10using MediaBrowser.Controller.Entities;
 11using MediaBrowser.Controller.Library;
 12using MediaBrowser.Model.Globalization;
 13using MediaBrowser.Model.Tasks;
 14
 15namespace Jellyfin.MediaEncoding.Hls.ScheduledTasks;
 16
 17/// <inheritdoc />
 18public class KeyframeExtractionScheduledTask : IScheduledTask
 19{
 20    private const int Pagesize = 1000;
 21
 22    private readonly ILocalizationManager _localizationManager;
 23    private readonly ILibraryManager _libraryManager;
 24    private readonly IKeyframeExtractor[] _keyframeExtractors;
 025    private static readonly BaseItemKind[] _itemTypes = [BaseItemKind.Episode, BaseItemKind.Movie];
 26
 27    /// <summary>
 28    /// Initializes a new instance of the <see cref="KeyframeExtractionScheduledTask"/> class.
 29    /// </summary>
 30    /// <param name="localizationManager">An instance of the <see cref="ILocalizationManager"/> interface.</param>
 31    /// <param name="libraryManager">An instance of the <see cref="ILibraryManager"/> interface.</param>
 32    /// <param name="keyframeExtractors">The keyframe extractors.</param>
 33    public KeyframeExtractionScheduledTask(ILocalizationManager localizationManager, ILibraryManager libraryManager, IEn
 2134    {
 2135        _localizationManager = localizationManager;
 2136        _libraryManager = libraryManager;
 2137        _keyframeExtractors = keyframeExtractors.OrderByDescending(e => e.IsMetadataBased).ToArray();
 2138    }
 39
 40    /// <inheritdoc />
 041    public string Name => _localizationManager.GetLocalizedString("TaskKeyframeExtractor");
 42
 43    /// <inheritdoc />
 044    public string Key => "KeyframeExtraction";
 45
 46    /// <inheritdoc />
 047    public string Description => _localizationManager.GetLocalizedString("TaskKeyframeExtractorDescription");
 48
 49    /// <inheritdoc />
 050    public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory");
 51
 52    /// <inheritdoc />
 53    public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
 054    {
 055        var query = new InternalItemsQuery
 056        {
 057            MediaTypes = [MediaType.Video],
 058            IsVirtualItem = false,
 059            IncludeItemTypes = _itemTypes,
 060            DtoOptions = new DtoOptions(true),
 061            SourceTypes = [SourceType.Library],
 062            Recursive = true,
 063            IncludeOwnedItems = true,
 064            Limit = Pagesize
 065        };
 66
 067        var numberOfVideos = _libraryManager.GetCount(query);
 68
 069        var startIndex = 0;
 070        var numComplete = 0;
 71
 072        while (startIndex < numberOfVideos)
 073        {
 074            query.StartIndex = startIndex;
 75
 076            var videos = _libraryManager.GetItemList(query);
 077            foreach (var video in videos)
 078            {
 079                cancellationToken.ThrowIfCancellationRequested();
 80
 81                // Only local files supported
 082                var path = video.Path;
 083                if (File.Exists(path))
 084                {
 085                    foreach (var extractor in _keyframeExtractors)
 086                    {
 87                        // The cache decorator will make sure to save the keyframes
 088                        if (extractor.TryExtractKeyframes(video.Id, path, out _))
 089                        {
 090                            break;
 91                        }
 092                    }
 093                }
 94
 95                // Update progress
 096                numComplete++;
 097                double percent = (double)numComplete / numberOfVideos;
 098                progress.Report(100 * percent);
 099            }
 100
 0101            startIndex += Pagesize;
 0102        }
 103
 0104        progress.Report(100);
 0105        return Task.CompletedTask;
 0106    }
 107
 108    /// <inheritdoc />
 21109    public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() => [];
 110}