< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.ScheduledTasks.Tasks.ChapterImagesTask
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
Line coverage
85%
Covered lines: 18
Uncovered lines: 3
Coverable lines: 21
Total lines: 177
Line coverage: 85.7%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

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

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.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.Extensions;
 9using MediaBrowser.Common.Configuration;
 10using MediaBrowser.Controller.Dto;
 11using MediaBrowser.Controller.Entities;
 12using MediaBrowser.Controller.Library;
 13using MediaBrowser.Controller.MediaEncoding;
 14using MediaBrowser.Controller.Persistence;
 15using MediaBrowser.Controller.Providers;
 16using MediaBrowser.Model.Globalization;
 17using MediaBrowser.Model.IO;
 18using MediaBrowser.Model.Tasks;
 19using Microsoft.Extensions.Logging;
 20
 21namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 22{
 23    /// <summary>
 24    /// Class ChapterImagesTask.
 25    /// </summary>
 26    public class ChapterImagesTask : IScheduledTask
 27    {
 28        private readonly ILogger<ChapterImagesTask> _logger;
 29        private readonly ILibraryManager _libraryManager;
 30        private readonly IItemRepository _itemRepo;
 31        private readonly IApplicationPaths _appPaths;
 32        private readonly IEncodingManager _encodingManager;
 33        private readonly IFileSystem _fileSystem;
 34        private readonly ILocalizationManager _localization;
 35
 36        /// <summary>
 37        /// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
 38        /// </summary>
 39        /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
 40        /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
 41        /// <param name="itemRepo">Instance of the <see cref="IItemRepository"/> interface.</param>
 42        /// <param name="appPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
 43        /// <param name="encodingManager">Instance of the <see cref="IEncodingManager"/> interface.</param>
 44        /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
 45        /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
 46        public ChapterImagesTask(
 47            ILogger<ChapterImagesTask> logger,
 48            ILibraryManager libraryManager,
 49            IItemRepository itemRepo,
 50            IApplicationPaths appPaths,
 51            IEncodingManager encodingManager,
 52            IFileSystem fileSystem,
 53            ILocalizationManager localization)
 54        {
 2255            _logger = logger;
 2256            _libraryManager = libraryManager;
 2257            _itemRepo = itemRepo;
 2258            _appPaths = appPaths;
 2259            _encodingManager = encodingManager;
 2260            _fileSystem = fileSystem;
 2261            _localization = localization;
 2262        }
 63
 64        /// <inheritdoc />
 2265        public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages");
 66
 67        /// <inheritdoc />
 068        public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription");
 69
 70        /// <inheritdoc />
 071        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 72
 73        /// <inheritdoc />
 074        public string Key => "RefreshChapterImages";
 75
 76        /// <inheritdoc />
 77        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 78        {
 2279            return
 2280            [
 2281                new TaskTriggerInfo
 2282                {
 2283                    Type = TaskTriggerInfo.TriggerDaily,
 2284                    TimeOfDayTicks = TimeSpan.FromHours(2).Ticks,
 2285                    MaxRuntimeTicks = TimeSpan.FromHours(4).Ticks
 2286                }
 2287            ];
 88        }
 89
 90        /// <inheritdoc />
 91        public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
 92        {
 93            var videos = _libraryManager.GetItemList(new InternalItemsQuery
 94            {
 95                MediaTypes = [MediaType.Video],
 96                IsFolder = false,
 97                Recursive = true,
 98                DtoOptions = new DtoOptions(false)
 99                {
 100                    EnableImages = false
 101                },
 102                SourceTypes = [SourceType.Library],
 103                IsVirtualItem = false
 104            })
 105            .OfType<Video>()
 106            .ToList();
 107
 108            var numComplete = 0;
 109
 110            var failHistoryPath = Path.Combine(_appPaths.CachePath, "chapter-failures.txt");
 111
 112            List<string> previouslyFailedImages;
 113
 114            if (File.Exists(failHistoryPath))
 115            {
 116                try
 117                {
 118                    previouslyFailedImages = (await File.ReadAllTextAsync(failHistoryPath, cancellationToken).ConfigureA
 119                        .Split('|', StringSplitOptions.RemoveEmptyEntries)
 120                        .ToList();
 121                }
 122                catch (IOException)
 123                {
 124                    previouslyFailedImages = new List<string>();
 125                }
 126            }
 127            else
 128            {
 129                previouslyFailedImages = new List<string>();
 130            }
 131
 132            var directoryService = new DirectoryService(_fileSystem);
 133
 134            foreach (var video in videos)
 135            {
 136                cancellationToken.ThrowIfCancellationRequested();
 137
 138                var key = video.Path + video.DateModified.Ticks;
 139
 140                var extract = !previouslyFailedImages.Contains(key, StringComparison.OrdinalIgnoreCase);
 141
 142                try
 143                {
 144                    var chapters = _itemRepo.GetChapters(video);
 145
 146                    var success = await _encodingManager.RefreshChapterImages(video, directoryService, chapters, extract
 147
 148                    if (!success)
 149                    {
 150                        previouslyFailedImages.Add(key);
 151
 152                        var parentPath = Path.GetDirectoryName(failHistoryPath);
 153                        if (parentPath is not null)
 154                        {
 155                            Directory.CreateDirectory(parentPath);
 156                        }
 157
 158                        string text = string.Join('|', previouslyFailedImages);
 159                        await File.WriteAllTextAsync(failHistoryPath, text, cancellationToken).ConfigureAwait(false);
 160                    }
 161
 162                    numComplete++;
 163                    double percent = numComplete;
 164                    percent /= videos.Count;
 165
 166                    progress.Report(100 * percent);
 167                }
 168                catch (ObjectDisposedException ex)
 169                {
 170                    // TODO Investigate and properly fix.
 171                    _logger.LogError(ex, "Object Disposed");
 172                    break;
 173                }
 174            }
 175        }
 176    }
 177}