< 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: 224
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.Entities;
 18using MediaBrowser.Model.Globalization;
 19using MediaBrowser.Model.Providers;
 20using MediaBrowser.Model.Tasks;
 21using Microsoft.Extensions.Logging;
 22
 23namespace MediaBrowser.Providers.MediaInfo
 24{
 25    public class SubtitleScheduledTask : IScheduledTask
 26    {
 27        private readonly ILibraryManager _libraryManager;
 28        private readonly IServerConfigurationManager _config;
 29        private readonly ISubtitleManager _subtitleManager;
 30        private readonly ILogger<SubtitleScheduledTask> _logger;
 31        private readonly ILocalizationManager _localization;
 32
 33        public SubtitleScheduledTask(
 34            ILibraryManager libraryManager,
 35            IServerConfigurationManager config,
 36            ISubtitleManager subtitleManager,
 37            ILogger<SubtitleScheduledTask> logger,
 38            ILocalizationManager localization)
 39        {
 2240            _libraryManager = libraryManager;
 2241            _config = config;
 2242            _subtitleManager = subtitleManager;
 2243            _logger = logger;
 2244            _localization = localization;
 2245        }
 46
 2247        public string Name => _localization.GetLocalizedString("TaskDownloadMissingSubtitles");
 48
 049        public string Description => _localization.GetLocalizedString("TaskDownloadMissingSubtitlesDescription");
 50
 051        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 52
 053        public string Key => "DownloadSubtitles";
 54
 055        public bool IsHidden => false;
 56
 057        public bool IsEnabled => true;
 58
 059        public bool IsLogged => true;
 60
 61        private SubtitleOptions GetOptions()
 62        {
 063            return _config.GetConfiguration<SubtitleOptions>("subtitles");
 64        }
 65
 66        /// <inheritdoc />
 67        public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
 68        {
 69            var options = GetOptions();
 70
 71            var types = new[] { BaseItemKind.Episode, BaseItemKind.Movie };
 72
 73            var dict = new Dictionary<Guid, BaseItem>();
 74
 75            foreach (var library in _libraryManager.RootFolder.Children.ToList())
 76            {
 77                var libraryOptions = _libraryManager.GetLibraryOptions(library);
 78
 79                string[] subtitleDownloadLanguages;
 80                bool skipIfEmbeddedSubtitlesPresent;
 81                bool skipIfAudioTrackMatches;
 82
 83                if (libraryOptions.SubtitleDownloadLanguages is null)
 84                {
 85                    subtitleDownloadLanguages = options.DownloadLanguages;
 86                    skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent;
 87                    skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches;
 88                }
 89                else
 90                {
 91                    subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
 92                    skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
 93                    skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
 94                }
 95
 96                foreach (var lang in subtitleDownloadLanguages)
 97                {
 98                    var query = new InternalItemsQuery
 99                    {
 100                        MediaTypes = new[] { MediaType.Video },
 101                        IsVirtualItem = false,
 102                        IncludeItemTypes = types,
 103                        DtoOptions = new DtoOptions(true),
 104                        SourceTypes = new[] { SourceType.Library },
 105                        Parent = library,
 106                        Recursive = true
 107                    };
 108
 109                    if (skipIfAudioTrackMatches)
 110                    {
 111                        query.HasNoAudioTrackWithLanguage = lang;
 112                    }
 113
 114                    if (skipIfEmbeddedSubtitlesPresent)
 115                    {
 116                        // Exclude if it already has any subtitles of the same language
 117                        query.HasNoSubtitleTrackWithLanguage = lang;
 118                    }
 119                    else
 120                    {
 121                        // Exclude if it already has external subtitles of the same language
 122                        query.HasNoExternalSubtitleTrackWithLanguage = lang;
 123                    }
 124
 125                    var videosByLanguage = _libraryManager.GetItemList(query);
 126
 127                    foreach (var video in videosByLanguage)
 128                    {
 129                        dict[video.Id] = video;
 130                    }
 131                }
 132            }
 133
 134            var videos = dict.Values.ToList();
 135            if (videos.Count == 0)
 136            {
 137                return;
 138            }
 139
 140            var numComplete = 0;
 141
 142            foreach (var video in videos)
 143            {
 144                cancellationToken.ThrowIfCancellationRequested();
 145
 146                try
 147                {
 148                    await DownloadSubtitles(video as Video, options, cancellationToken).ConfigureAwait(false);
 149                }
 150                catch (Exception ex)
 151                {
 152                    _logger.LogError(ex, "Error downloading subtitles for {Path}", video.Path);
 153                }
 154
 155                // Update progress
 156                numComplete++;
 157                double percent = numComplete;
 158                percent /= videos.Count;
 159
 160                progress.Report(100 * percent);
 161            }
 162        }
 163
 164        private async Task<bool> DownloadSubtitles(Video video, SubtitleOptions options, CancellationToken cancellationT
 165        {
 166            var mediaStreams = video.GetMediaStreams();
 167
 168            var libraryOptions = _libraryManager.GetLibraryOptions(video);
 169
 170            string[] subtitleDownloadLanguages;
 171            bool skipIfEmbeddedSubtitlesPresent;
 172            bool skipIfAudioTrackMatches;
 173            bool requirePerfectMatch;
 174
 175            if (libraryOptions.SubtitleDownloadLanguages is null)
 176            {
 177                subtitleDownloadLanguages = options.DownloadLanguages;
 178                skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent;
 179                skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches;
 180                requirePerfectMatch = options.RequirePerfectMatch;
 181            }
 182            else
 183            {
 184                subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
 185                skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
 186                skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
 187                requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch;
 188            }
 189
 190            var downloadedLanguages = await new SubtitleDownloader(
 191                _logger,
 192                _subtitleManager).DownloadSubtitles(
 193                    video,
 194                    mediaStreams,
 195                    skipIfEmbeddedSubtitlesPresent,
 196                    skipIfAudioTrackMatches,
 197                    requirePerfectMatch,
 198                    subtitleDownloadLanguages,
 199                    libraryOptions.DisabledSubtitleFetchers,
 200                    libraryOptions.SubtitleFetcherOrder,
 201                    true,
 202                    cancellationToken).ConfigureAwait(false);
 203
 204            // Rescan
 205            if (downloadedLanguages.Count > 0)
 206            {
 207                await video.RefreshMetadata(cancellationToken).ConfigureAwait(false);
 208                return false;
 209            }
 210
 211            return true;
 212        }
 213
 214        /// <inheritdoc />
 215        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 216        {
 22217            return new[]
 22218            {
 22219                // Every so often
 22220                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Tic
 22221            };
 222        }
 223    }
 224}