< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.ScheduledTasks.Tasks.PeopleValidationTask
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
Line coverage
45%
Covered lines: 5
Uncovered lines: 6
Coverable lines: 11
Total lines: 129
Line coverage: 45.4%
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%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs

#LineLine coverage
 1using System;
 2using System.Buffers;
 3using System.Collections.Generic;
 4using System.Linq;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using Jellyfin.Database.Implementations;
 8using MediaBrowser.Controller.Library;
 9using MediaBrowser.Model.Globalization;
 10using MediaBrowser.Model.Tasks;
 11using Microsoft.EntityFrameworkCore;
 12
 13namespace Emby.Server.Implementations.ScheduledTasks.Tasks;
 14
 15/// <summary>
 16/// Class PeopleValidationTask.
 17/// </summary>
 18public class PeopleValidationTask : IScheduledTask, IConfigurableScheduledTask
 19{
 20    private readonly ILibraryManager _libraryManager;
 21    private readonly ILocalizationManager _localization;
 22    private readonly IDbContextFactory<JellyfinDbContext> _dbContextFactory;
 23
 24    /// <summary>
 25    /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
 26    /// </summary>
 27    /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
 28    /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
 29    /// <param name="dbContextFactory">Instance of the <see cref="IDbContextFactory{TContext}"/> interface.</param>
 30    public PeopleValidationTask(ILibraryManager libraryManager, ILocalizationManager localization, IDbContextFactory<Jel
 31    {
 2132        _libraryManager = libraryManager;
 2133        _localization = localization;
 2134        _dbContextFactory = dbContextFactory;
 2135    }
 36
 37    /// <inheritdoc />
 2138    public string Name => _localization.GetLocalizedString("TaskRefreshPeople");
 39
 40    /// <inheritdoc />
 041    public string Description => _localization.GetLocalizedString("TaskRefreshPeopleDescription");
 42
 43    /// <inheritdoc />
 044    public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 45
 46    /// <inheritdoc />
 047    public string Key => "RefreshPeople";
 48
 49    /// <inheritdoc />
 050    public bool IsHidden => false;
 51
 52    /// <inheritdoc />
 053    public bool IsEnabled => true;
 54
 55    /// <inheritdoc />
 056    public bool IsLogged => true;
 57
 58    /// <summary>
 59    /// Creates the triggers that define when the task will run.
 60    /// </summary>
 61    /// <returns>An <see cref="IEnumerable{TaskTriggerInfo}"/> containing the default trigger infos for this task.</retu
 62    public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 63    {
 64        yield return new TaskTriggerInfo
 65        {
 66            Type = TaskTriggerInfoType.IntervalTrigger,
 67            IntervalTicks = TimeSpan.FromDays(7).Ticks
 68        };
 69    }
 70
 71    /// <inheritdoc />
 72    public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
 73    {
 74        IProgress<double> subProgress = new Progress<double>((val) => progress.Report(val / 2));
 75        await _libraryManager.ValidatePeopleAsync(subProgress, cancellationToken).ConfigureAwait(false);
 76
 77        subProgress = new Progress<double>((val) => progress.Report((val / 2) + 50));
 78        var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
 79        await using (context.ConfigureAwait(false))
 80        {
 81            var dupQuery = context.Peoples
 82                    .GroupBy(e => new { e.Name, e.PersonType })
 83                    .Where(e => e.Count() > 1)
 84                    .Select(e => e.Select(f => f.Id).ToArray());
 85
 86            var total = dupQuery.Count();
 87
 88            const int PartitionSize = 100;
 89            var iterator = 0;
 90            int itemCounter;
 91            var buffer = ArrayPool<Guid[]>.Shared.Rent(PartitionSize)!;
 92            try
 93            {
 94                do
 95                {
 96                    itemCounter = 0;
 97                    await foreach (var item in dupQuery
 98                        .Take(PartitionSize)
 99                        .AsAsyncEnumerable()
 100                        .WithCancellation(cancellationToken)
 101                        .ConfigureAwait(false))
 102                    {
 103                        buffer[itemCounter++] = item;
 104                    }
 105
 106                    for (int i = 0; i < itemCounter; i++)
 107                    {
 108                        var item = buffer[i];
 109                        var reference = item[0];
 110                        var dups = item[1..];
 111                        await context.PeopleBaseItemMap.WhereOneOrMany(dups, e => e.PeopleId)
 112                            .ExecuteUpdateAsync(e => e.SetProperty(f => f.PeopleId, reference), cancellationToken)
 113                            .ConfigureAwait(false);
 114                        await context.Peoples.Where(e => dups.Contains(e.Id)).ExecuteDeleteAsync(cancellationToken).Conf
 115                        subProgress.Report(100f / total * ((iterator * PartitionSize) + i));
 116                    }
 117
 118                    iterator++;
 119                } while (itemCounter == PartitionSize && !cancellationToken.IsCancellationRequested);
 120            }
 121            finally
 122            {
 123                ArrayPool<Guid[]>.Shared.Return(buffer);
 124            }
 125
 126            subProgress.Report(100);
 127        }
 128    }
 129}