< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.MediaInfo.SubtitleScheduledTask
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
Line coverage
63%
Covered lines: 12
Uncovered lines: 7
Coverable lines: 19
Total lines: 223
Line coverage: 63.1%
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%
get_IsHidden()100%210%
get_IsEnabled()100%210%
get_IsLogged()100%210%
GetOptions()100%210%
GetDefaultTriggers()100%11100%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Linq;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using Jellyfin.Data.Enums;
 11using MediaBrowser.Common.Configuration;
 12using MediaBrowser.Controller.Configuration;
 13using MediaBrowser.Controller.Dto;
 14using MediaBrowser.Controller.Entities;
 15using MediaBrowser.Controller.Library;
 16using MediaBrowser.Controller.Subtitles;
 17using MediaBrowser.Model.Globalization;
 18using MediaBrowser.Model.Providers;
 19using MediaBrowser.Model.Tasks;
 20using Microsoft.Extensions.Logging;
 21
 22namespace MediaBrowser.Providers.MediaInfo
 23{
 24    public class SubtitleScheduledTask : IScheduledTask
 25    {
 26        private readonly ILibraryManager _libraryManager;
 27        private readonly IServerConfigurationManager _config;
 28        private readonly ISubtitleManager _subtitleManager;
 29        private readonly ILogger<SubtitleScheduledTask> _logger;
 30        private readonly ILocalizationManager _localization;
 31
 32        public SubtitleScheduledTask(
 33            ILibraryManager libraryManager,
 34            IServerConfigurationManager config,
 35            ISubtitleManager subtitleManager,
 36            ILogger<SubtitleScheduledTask> logger,
 37            ILocalizationManager localization)
 38        {
 2139            _libraryManager = libraryManager;
 2140            _config = config;
 2141            _subtitleManager = subtitleManager;
 2142            _logger = logger;
 2143            _localization = localization;
 2144        }
 45
 2146        public string Name => _localization.GetLocalizedString("TaskDownloadMissingSubtitles");
 47
 048        public string Description => _localization.GetLocalizedString("TaskDownloadMissingSubtitlesDescription");
 49
 050        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 51
 052        public string Key => "DownloadSubtitles";
 53
 054        public bool IsHidden => false;
 55
 056        public bool IsEnabled => true;
 57
 058        public bool IsLogged => true;
 59
 60        private SubtitleOptions GetOptions()
 61        {
 062            return _config.GetConfiguration<SubtitleOptions>("subtitles");
 63        }
 64
 65        /// <inheritdoc />
 66        public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
 67        {
 68            var options = GetOptions();
 69
 70            var types = new[] { BaseItemKind.Episode, BaseItemKind.Movie };
 71
 72            var dict = new Dictionary<Guid, BaseItem>();
 73
 74            foreach (var library in _libraryManager.RootFolder.Children.ToList())
 75            {
 76                var libraryOptions = _libraryManager.GetLibraryOptions(library);
 77
 78                string[] subtitleDownloadLanguages;
 79                bool skipIfEmbeddedSubtitlesPresent;
 80                bool skipIfAudioTrackMatches;
 81
 82                if (libraryOptions.SubtitleDownloadLanguages is null)
 83                {
 84                    subtitleDownloadLanguages = options.DownloadLanguages;
 85                    skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent;
 86                    skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches;
 87                }
 88                else
 89                {
 90                    subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
 91                    skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
 92                    skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
 93                }
 94
 95                foreach (var lang in subtitleDownloadLanguages)
 96                {
 97                    var query = new InternalItemsQuery
 98                    {
 99                        MediaTypes = new[] { MediaType.Video },
 100                        IsVirtualItem = false,
 101                        IncludeItemTypes = types,
 102                        DtoOptions = new DtoOptions(true),
 103                        SourceTypes = new[] { SourceType.Library },
 104                        Parent = library,
 105                        Recursive = true
 106                    };
 107
 108                    if (skipIfAudioTrackMatches)
 109                    {
 110                        query.HasNoAudioTrackWithLanguage = lang;
 111                    }
 112
 113                    if (skipIfEmbeddedSubtitlesPresent)
 114                    {
 115                        // Exclude if it already has any subtitles of the same language
 116                        query.HasNoSubtitleTrackWithLanguage = lang;
 117                    }
 118                    else
 119                    {
 120                        // Exclude if it already has external subtitles of the same language
 121                        query.HasNoExternalSubtitleTrackWithLanguage = lang;
 122                    }
 123
 124                    var videosByLanguage = _libraryManager.GetItemList(query);
 125
 126                    foreach (var video in videosByLanguage)
 127                    {
 128                        dict[video.Id] = video;
 129                    }
 130                }
 131            }
 132
 133            var videos = dict.Values.ToList();
 134            if (videos.Count == 0)
 135            {
 136                return;
 137            }
 138
 139            var numComplete = 0;
 140
 141            foreach (var video in videos)
 142            {
 143                cancellationToken.ThrowIfCancellationRequested();
 144
 145                try
 146                {
 147                    await DownloadSubtitles(video as Video, options, cancellationToken).ConfigureAwait(false);
 148                }
 149                catch (Exception ex)
 150                {
 151                    _logger.LogError(ex, "Error downloading subtitles for {Path}", video.Path);
 152                }
 153
 154                // Update progress
 155                numComplete++;
 156                double percent = numComplete;
 157                percent /= videos.Count;
 158
 159                progress.Report(100 * percent);
 160            }
 161        }
 162
 163        private async Task<bool> DownloadSubtitles(Video video, SubtitleOptions options, CancellationToken cancellationT
 164        {
 165            var mediaStreams = video.GetMediaStreams();
 166
 167            var libraryOptions = _libraryManager.GetLibraryOptions(video);
 168
 169            string[] subtitleDownloadLanguages;
 170            bool skipIfEmbeddedSubtitlesPresent;
 171            bool skipIfAudioTrackMatches;
 172            bool requirePerfectMatch;
 173
 174            if (libraryOptions.SubtitleDownloadLanguages is null)
 175            {
 176                subtitleDownloadLanguages = options.DownloadLanguages;
 177                skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent;
 178                skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches;
 179                requirePerfectMatch = options.RequirePerfectMatch;
 180            }
 181            else
 182            {
 183                subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
 184                skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
 185                skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
 186                requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch;
 187            }
 188
 189            var downloadedLanguages = await new SubtitleDownloader(
 190                _logger,
 191                _subtitleManager).DownloadSubtitles(
 192                    video,
 193                    mediaStreams,
 194                    skipIfEmbeddedSubtitlesPresent,
 195                    skipIfAudioTrackMatches,
 196                    requirePerfectMatch,
 197                    subtitleDownloadLanguages,
 198                    libraryOptions.DisabledSubtitleFetchers,
 199                    libraryOptions.SubtitleFetcherOrder,
 200                    true,
 201                    cancellationToken).ConfigureAwait(false);
 202
 203            // Rescan
 204            if (downloadedLanguages.Count > 0)
 205            {
 206                await video.RefreshMetadata(cancellationToken).ConfigureAwait(false);
 207                return false;
 208            }
 209
 210            return true;
 211        }
 212
 213        /// <inheritdoc />
 214        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 215        {
 21216            return new[]
 21217            {
 21218                // Every so often
 21219                new TaskTriggerInfo { Type = TaskTriggerInfoType.IntervalTrigger, IntervalTicks = TimeSpan.FromHours(24)
 21220            };
 221        }
 222    }
 223}