Merge pull request #7321 from Bond-009/warn61

This commit is contained in:
Cody Robibero 2022-02-16 20:47:22 -07:00 committed by GitHub
commit 9930efec22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 194 additions and 93 deletions

View File

@ -150,7 +150,7 @@ namespace Emby.Server.Implementations
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param> /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
/// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param> /// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
/// <param name="startupConfig">The <see cref="IConfiguration" /> interface.</param> /// <param name="startupConfig">The <see cref="IConfiguration" /> interface.</param>
public ApplicationHost( protected ApplicationHost(
IServerApplicationPaths applicationPaths, IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IStartupOptions options, IStartupOptions options,

View File

@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Channels
/// <summary> /// <summary>
/// The LiveTV channel manager. /// The LiveTV channel manager.
/// </summary> /// </summary>
public class ChannelManager : IChannelManager public class ChannelManager : IChannelManager, IDisposable
{ {
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager; private readonly IUserDataManager _userDataManager;
@ -52,6 +52,7 @@ namespace Emby.Server.Implementations.Channels
private readonly IMemoryCache _memoryCache; private readonly IMemoryCache _memoryCache;
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private bool _disposed = false;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ChannelManager"/> class. /// Initializes a new instance of the <see cref="ChannelManager"/> class.
@ -1213,5 +1214,31 @@ namespace Emby.Server.Implementations.Channels
return result; return result;
} }
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_resourcePool?.Dispose();
}
_disposed = true;
}
} }
} }

View File

@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Channels
public string Key => "RefreshInternetChannels"; public string Key => "RefreshInternetChannels";
/// <inheritdoc /> /// <inheritdoc />
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
var manager = (ChannelManager)_channelManager; var manager = (ChannelManager)_channelManager;

View File

@ -390,6 +390,7 @@ namespace Emby.Server.Implementations.Data
return userData; return userData;
} }
#pragma warning disable CA2215
/// <inheritdoc/> /// <inheritdoc/>
/// <remarks> /// <remarks>
/// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and /// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
@ -398,6 +399,10 @@ namespace Emby.Server.Implementations.Data
/// </remarks> /// </remarks>
protected override void Dispose(bool dispose) protected override void Dispose(bool dispose)
{ {
// The write lock and connection for the item repository are shared with the user data repository
// since they point to the same database. The item repo has responsibility for disposing these two objects,
// so the user data repo should not attempt to dispose them as well
} }
#pragma warning restore CA2215
} }
} }

View File

@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Images
{ {
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) protected BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
: base(fileSystem, providerManager, applicationPaths, imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;

View File

@ -1007,14 +1007,8 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId); return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
} }
/// <summary> /// <inheritdoc />
/// Validate and refresh the People sub-set of the IBN. public Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// The items are stored in the db but not loaded into memory until actually requested by an operation.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{ {
// Ensure the location is available. // Ensure the location is available.
Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath); Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);

View File

@ -24,7 +24,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
public class EncodedRecorder : IRecorder public class EncodedRecorder : IRecorder, IDisposable
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
@ -36,6 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private Stream _logFileStream; private Stream _logFileStream;
private string _targetPath; private string _targetPath;
private Process _process; private Process _process;
private bool _disposed = false;
public EncodedRecorder( public EncodedRecorder(
ILogger logger, ILogger logger,
@ -323,5 +324,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogError(ex, "Error reading ffmpeg recording log"); _logger.LogError(ex, "Error reading ffmpeg recording log");
} }
} }
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_logFileStream?.Dispose();
_process?.Dispose();
}
_logFileStream = null;
_process = null;
_disposed = true;
}
} }
} }

View File

@ -28,7 +28,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.Listings namespace Emby.Server.Implementations.LiveTv.Listings
{ {
public class SchedulesDirect : IListingsProvider public class SchedulesDirect : IListingsProvider, IDisposable
{ {
private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
@ -39,6 +39,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>(); private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private DateTime _lastErrorResponse; private DateTime _lastErrorResponse;
private bool _disposed = false;
public SchedulesDirect( public SchedulesDirect(
ILogger<SchedulesDirect> logger, ILogger<SchedulesDirect> logger,
@ -58,8 +59,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
var dates = new List<string>(); var dates = new List<string>();
var start = new List<DateTime> { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date; var start = new[] { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
var end = new List<DateTime> { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date; var end = new[] { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
while (start <= end) while (start <= end)
{ {
@ -822,5 +823,31 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return list; return list;
} }
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_tokenSemaphore?.Dispose();
}
_disposed = true;
}
} }
} }

View File

@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.LiveTv
public string Key => "RefreshGuide"; public string Key => "RefreshGuide";
/// <inheritdoc /> /// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
var manager = (LiveTvManager)_liveTvManager; var manager = (LiveTvManager)_liveTvManager;

View File

@ -414,7 +414,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value)); CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value));
} }
await ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false); await ScheduledTask.ExecuteAsync(progress, CurrentCancellationTokenSource.Token).ConfigureAwait(false);
status = TaskCompletionStatus.Completed; status = TaskCompletionStatus.Completed;
} }
@ -757,6 +757,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
var trigger = triggerInfo.Item2; var trigger = triggerInfo.Item2;
trigger.Triggered -= OnTriggerTriggered; trigger.Triggered -= OnTriggerTriggered;
trigger.Stop(); trigger.Stop();
if (trigger is IDisposable disposable)
{
disposable.Dispose();
}
} }
} }
} }

View File

@ -88,13 +88,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
var videos = _libraryManager.GetItemList(new InternalItemsQuery var videos = _libraryManager.GetItemList(new InternalItemsQuery
{ {

View File

@ -57,12 +57,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
public bool IsLogged => true; public bool IsLogged => true;
/// <inheritdoc /> /// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays; var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
if (!retentionDays.HasValue || retentionDays < 0) if (!retentionDays.HasValue || retentionDays < 0)
{ {
throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}"); throw new InvalidOperationException($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
} }
var startDate = DateTime.UtcNow.AddDays(-retentionDays.Value); var startDate = DateTime.UtcNow.AddDays(-retentionDays.Value);

View File

@ -79,19 +79,14 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
var minDateModified = DateTime.UtcNow.AddDays(-30); var minDateModified = DateTime.UtcNow.AddDays(-30);
try try
{ {
DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.CachePath, minDateModified, progress); DeleteCacheFilesFromDirectory(_applicationPaths.CachePath, minDateModified, progress, cancellationToken);
} }
catch (DirectoryNotFoundException) catch (DirectoryNotFoundException)
{ {
@ -104,7 +99,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try try
{ {
DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.TempDirectory, minDateModified, progress); DeleteCacheFilesFromDirectory(_applicationPaths.TempDirectory, minDateModified, progress, cancellationToken);
} }
catch (DirectoryNotFoundException) catch (DirectoryNotFoundException)
{ {
@ -117,11 +112,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary> /// <summary>
/// Deletes the cache files from directory with a last write time less than a given date. /// Deletes the cache files from directory with a last write time less than a given date.
/// </summary> /// </summary>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param> /// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param> /// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress) /// <param name="cancellationToken">The task cancellation token.</param>
private void DeleteCacheFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var filesToDelete = _fileSystem.GetFiles(directory, true) var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified) .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)

View File

@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
// Delete log files more than n days old // Delete log files more than n days old
var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays); var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays);

View File

@ -78,18 +78,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
var minDateModified = DateTime.UtcNow.AddDays(-1); var minDateModified = DateTime.UtcNow.AddDays(-1);
progress.Report(50); progress.Report(50);
DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodePath(), minDateModified, progress); DeleteTempFilesFromDirectory(_configurationManager.GetTranscodePath(), minDateModified, progress, cancellationToken);
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -97,11 +92,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary> /// <summary>
/// Deletes the transcoded temp files from directory with a last write time less than a given date. /// Deletes the transcoded temp files from directory with a last write time less than a given date.
/// </summary> /// </summary>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param> /// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param> /// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
private void DeleteTempFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress) /// <param name="cancellationToken">The task cancellation token.</param>
private void DeleteTempFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var filesToDelete = _fileSystem.GetFiles(directory, true) var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified) .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)

View File

@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
_logger.LogInformation("Optimizing and vacuuming jellyfin.db..."); _logger.LogInformation("Optimizing and vacuuming jellyfin.db...");

View File

@ -62,15 +62,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Returns the task to be executed. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
return _libraryManager.ValidatePeople(cancellationToken, progress); return _libraryManager.ValidatePeopleAsync(progress, cancellationToken);
} }
} }
} }

View File

@ -68,13 +68,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }; yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks };
} }
/// <summary> /// <inheritdoc />
/// Update installed plugins. public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns><see cref="Task" />.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
progress.Report(0); progress.Report(0);

View File

@ -58,13 +58,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}; };
} }
/// <summary> /// <inheritdoc />
/// Executes the internal. public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();

View File

@ -8,10 +8,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary> /// <summary>
/// Represents a task trigger that fires everyday. /// Represents a task trigger that fires everyday.
/// </summary> /// </summary>
public sealed class DailyTrigger : ITaskTrigger public sealed class DailyTrigger : ITaskTrigger, IDisposable
{ {
private readonly TimeSpan _timeOfDay; private readonly TimeSpan _timeOfDay;
private Timer? _timer; private Timer? _timer;
private bool _disposed = false;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DailyTrigger"/> class. /// Initializes a new instance of the <see cref="DailyTrigger"/> class.
@ -71,6 +72,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer() private void DisposeTimer()
{ {
_timer?.Dispose(); _timer?.Dispose();
_timer = null;
} }
/// <summary> /// <summary>
@ -80,5 +82,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{ {
Triggered?.Invoke(this, EventArgs.Empty); Triggered?.Invoke(this, EventArgs.Empty);
} }
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
} }
} }

View File

@ -9,11 +9,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary> /// <summary>
/// Represents a task trigger that runs repeatedly on an interval. /// Represents a task trigger that runs repeatedly on an interval.
/// </summary> /// </summary>
public sealed class IntervalTrigger : ITaskTrigger public sealed class IntervalTrigger : ITaskTrigger, IDisposable
{ {
private readonly TimeSpan _interval; private readonly TimeSpan _interval;
private DateTime _lastStartDate; private DateTime _lastStartDate;
private Timer? _timer; private Timer? _timer;
private bool _disposed = false;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="IntervalTrigger"/> class. /// Initializes a new instance of the <see cref="IntervalTrigger"/> class.
@ -89,6 +90,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer() private void DisposeTimer()
{ {
_timer?.Dispose(); _timer?.Dispose();
_timer = null;
} }
/// <summary> /// <summary>
@ -104,5 +106,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
Triggered(this, EventArgs.Empty); Triggered(this, EventArgs.Empty);
} }
} }
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
} }
} }

View File

@ -8,11 +8,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary> /// <summary>
/// Represents a task trigger that fires on a weekly basis. /// Represents a task trigger that fires on a weekly basis.
/// </summary> /// </summary>
public sealed class WeeklyTrigger : ITaskTrigger public sealed class WeeklyTrigger : ITaskTrigger, IDisposable
{ {
private readonly TimeSpan _timeOfDay; private readonly TimeSpan _timeOfDay;
private readonly DayOfWeek _dayOfWeek; private readonly DayOfWeek _dayOfWeek;
private Timer? _timer; private Timer? _timer;
private bool _disposed = false;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WeeklyTrigger"/> class. /// Initializes a new instance of the <see cref="WeeklyTrigger"/> class.
@ -94,6 +95,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer() private void DisposeTimer()
{ {
_timer?.Dispose(); _timer?.Dispose();
_timer = null;
} }
/// <summary> /// <summary>
@ -103,5 +105,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{ {
Triggered?.Invoke(this, EventArgs.Empty); Triggered?.Invoke(this, EventArgs.Empty);
} }
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
} }
} }

View File

@ -138,10 +138,10 @@ namespace MediaBrowser.Controller.Library
/// Validate and refresh the People sub-set of the IBN. /// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation. /// The items are stored in the db but not loaded into memory until actually requested by an operation.
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress); Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Reloads the root media folder. /// Reloads the root media folder.

View File

@ -36,10 +36,10 @@ namespace MediaBrowser.Model.Tasks
/// <summary> /// <summary>
/// Executes the task. /// Executes the task.
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task Execute(CancellationToken cancellationToken, IProgress<double> progress); Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the default triggers that define when the task will run. /// Gets the default triggers that define when the task will run.

View File

@ -63,7 +63,8 @@ namespace MediaBrowser.Providers.MediaInfo
return _config.GetConfiguration<SubtitleOptions>("subtitles"); return _config.GetConfiguration<SubtitleOptions>("subtitles");
} }
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) /// <inheritdoc />
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
var options = GetOptions(); var options = GetOptions();
@ -210,6 +211,7 @@ namespace MediaBrowser.Providers.MediaInfo
return true; return true;
} }
/// <inheritdoc />
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{ {
return new[] return new[]

View File

@ -57,6 +57,10 @@
</Rules> </Rules>
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design"> <Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design">
<!-- error on CA1001: Types that own disposable fields should be disposable -->
<Rule Id="CA1001" Action="Error" />
<!-- error on CA1012: Abstract types should not have public constructors -->
<Rule Id="CA1012" Action="Error" />
<!-- error on CA1063: Implement IDisposable correctly --> <!-- error on CA1063: Implement IDisposable correctly -->
<Rule Id="CA1063" Action="Error" /> <Rule Id="CA1063" Action="Error" />
<!-- error on CA1305: Specify IFormatProvider --> <!-- error on CA1305: Specify IFormatProvider -->
@ -80,6 +84,8 @@
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one <!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token --> or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
<Rule Id="CA2016" Action="Error" /> <Rule Id="CA2016" Action="Error" />
<!-- error on CA2215: Dispose methods should call base class dispose -->
<Rule Id="CA2215" Action="Error" />
<!-- error on CA2254: Template should be a static expression --> <!-- error on CA2254: Template should be a static expression -->
<Rule Id="CA2254" Action="Error" /> <Rule Id="CA2254" Action="Error" />

View File

@ -51,7 +51,7 @@ public class KeyframeExtractionScheduledTask : IScheduledTask
public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory"); public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory");
/// <inheritdoc /> /// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
var query = new InternalItemsQuery var query = new InternalItemsQuery
{ {