aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/ScheduledTasks
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/ScheduledTasks')
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs263
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs105
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs78
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs78
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs75
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs79
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs170
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs104
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs51
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs90
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs51
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs57
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs50
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs43
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs65
15 files changed, 859 insertions, 500 deletions
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 08bb39578..f2cdfeb16 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -1,57 +1,75 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
using System;
-using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Events;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class ScheduledTaskWorker
+ /// Class ScheduledTaskWorker.
/// </summary>
public class ScheduledTaskWorker : IScheduledTaskWorker
{
- public event EventHandler<GenericEventArgs<double>> TaskProgress;
-
- /// <summary>
- /// Gets or sets the scheduled task.
- /// </summary>
- /// <value>The scheduled task.</value>
- public IScheduledTask ScheduledTask { get; private set; }
-
/// <summary>
- /// Gets or sets the json serializer.
+ /// The options for the json Serializer.
/// </summary>
- /// <value>The json serializer.</value>
- private IJsonSerializer JsonSerializer { get; set; }
+ private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
/// <summary>
/// Gets or sets the application paths.
/// </summary>
/// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
+ private readonly IApplicationPaths _applicationPaths;
/// <summary>
- /// Gets the logger.
+ /// Gets or sets the logger.
/// </summary>
/// <value>The logger.</value>
- private ILogger Logger { get; set; }
+ private readonly ILogger _logger;
/// <summary>
- /// Gets the task manager.
+ /// Gets or sets the task manager.
/// </summary>
/// <value>The task manager.</value>
- private ITaskManager TaskManager { get; set; }
- private readonly IFileSystem _fileSystem;
+ private readonly ITaskManager _taskManager;
+
+ /// <summary>
+ /// The _last execution result sync lock.
+ /// </summary>
+ private readonly object _lastExecutionResultSyncLock = new object();
+
+ private bool _readFromFile = false;
+
+ /// <summary>
+ /// The _last execution result.
+ /// </summary>
+ private TaskResult _lastExecutionResult;
+
+ private Task _currentTask;
+
+ /// <summary>
+ /// The _triggers.
+ /// </summary>
+ private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers;
+
+ /// <summary>
+ /// The _id.
+ /// </summary>
+ private string _id;
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
@@ -59,7 +77,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="scheduledTask">The scheduled task.</param>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="taskManager">The task manager.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <exception cref="ArgumentNullException">
/// scheduledTask
@@ -70,50 +87,46 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// or
/// jsonSerializer
/// or
- /// logger
+ /// logger.
/// </exception>
- public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger, IFileSystem fileSystem)
+ public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger)
{
if (scheduledTask == null)
{
throw new ArgumentNullException(nameof(scheduledTask));
}
+
if (applicationPaths == null)
{
throw new ArgumentNullException(nameof(applicationPaths));
}
+
if (taskManager == null)
{
throw new ArgumentNullException(nameof(taskManager));
}
- if (jsonSerializer == null)
- {
- throw new ArgumentNullException(nameof(jsonSerializer));
- }
+
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
ScheduledTask = scheduledTask;
- ApplicationPaths = applicationPaths;
- TaskManager = taskManager;
- JsonSerializer = jsonSerializer;
- Logger = logger;
- _fileSystem = fileSystem;
+ _applicationPaths = applicationPaths;
+ _taskManager = taskManager;
+ _logger = logger;
InitTriggerEvents();
}
- private bool _readFromFile = false;
- /// <summary>
- /// The _last execution result
- /// </summary>
- private TaskResult _lastExecutionResult;
+ public event EventHandler<GenericEventArgs<double>> TaskProgress;
+
/// <summary>
- /// The _last execution result sync lock
+ /// Gets the scheduled task.
/// </summary>
- private readonly object _lastExecutionResultSyncLock = new object();
+ /// <value>The scheduled task.</value>
+ public IScheduledTask ScheduledTask { get; private set; }
+
/// <summary>
/// Gets the last execution result.
/// </summary>
@@ -130,21 +143,31 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
if (File.Exists(path))
{
- try
+ var bytes = File.ReadAllBytes(path);
+ if (bytes.Length > 0)
{
- _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path);
+ try
+ {
+ _lastExecutionResult = JsonSerializer.Deserialize<TaskResult>(bytes, _jsonOptions);
+ }
+ catch (JsonException ex)
+ {
+ _logger.LogError(ex, "Error deserializing {File}", path);
+ }
}
- catch (Exception ex)
+ else
{
- Logger.LogError(ex, "Error deserializing {File}", path);
+ _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path);
}
}
+
_readFromFile = true;
}
}
return _lastExecutionResult;
}
+
private set
{
_lastExecutionResult = value;
@@ -154,7 +177,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
lock (_lastExecutionResultSyncLock)
{
- JsonSerializer.SerializeToFile(value, path);
+ using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
+ using Utf8JsonWriter jsonStream = new Utf8JsonWriter(createStream);
+ JsonSerializer.Serialize(jsonStream, value, _jsonOptions);
}
}
}
@@ -178,7 +203,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
public string Category => ScheduledTask.Category;
/// <summary>
- /// Gets the current cancellation token
+ /// Gets or sets the current cancellation token.
/// </summary>
/// <value>The current cancellation token source.</value>
private CancellationTokenSource CurrentCancellationTokenSource { get; set; }
@@ -215,11 +240,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
public double? CurrentProgress { get; private set; }
/// <summary>
- /// The _triggers
- /// </summary>
- private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers;
- /// <summary>
- /// Gets the triggers that define when the task will run
+ /// Gets or sets the triggers that define when the task will run.
/// </summary>
/// <value>The triggers.</value>
private Tuple<TaskTriggerInfo, ITaskTrigger>[] InternalTriggers
@@ -245,10 +266,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Gets the triggers that define when the task will run
+ /// Gets or sets the triggers that define when the task will run.
/// </summary>
/// <value>The triggers.</value>
- /// <exception cref="ArgumentNullException">value</exception>
+ /// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception>
public TaskTriggerInfo[] Triggers
{
get
@@ -256,6 +277,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
var triggers = InternalTriggers;
return triggers.Select(i => i.Item1).ToArray();
}
+
set
{
if (value == null)
@@ -273,11 +295,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// The _id
- /// </summary>
- private string _id;
-
- /// <summary>
/// Gets the unique id.
/// </summary>
/// <value>The unique id.</value>
@@ -285,12 +302,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
get
{
- if (_id == null)
- {
- _id = ScheduledTask.GetType().FullName.GetMD5().ToString("N");
- }
-
- return _id;
+ return _id ??= ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
}
@@ -317,9 +329,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
trigger.Stop();
- trigger.Triggered -= trigger_Triggered;
- trigger.Triggered += trigger_Triggered;
- trigger.Start(LastExecutionResult, Logger, Name, isApplicationStartup);
+ trigger.Triggered -= OnTriggerTriggered;
+ trigger.Triggered += OnTriggerTriggered;
+ trigger.Start(LastExecutionResult, _logger, Name, isApplicationStartup);
}
}
@@ -328,36 +340,32 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- async void trigger_Triggered(object sender, EventArgs e)
+ private async void OnTriggerTriggered(object sender, EventArgs e)
{
var trigger = (ITaskTrigger)sender;
- var configurableTask = ScheduledTask as IConfigurableScheduledTask;
-
- if (configurableTask != null && !configurableTask.IsEnabled)
+ if (ScheduledTask is IConfigurableScheduledTask configurableTask && !configurableTask.IsEnabled)
{
return;
}
- Logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name);
+ _logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name);
trigger.Stop();
- TaskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions);
+ _taskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions);
await Task.Delay(1000).ConfigureAwait(false);
- trigger.Start(LastExecutionResult, Logger, Name, false);
+ trigger.Start(LastExecutionResult, _logger, Name, false);
}
- private Task _currentTask;
-
/// <summary>
- /// Executes the task
+ /// Executes the task.
/// </summary>
/// <param name="options">Task options.</param>
/// <returns>Task.</returns>
- /// <exception cref="InvalidOperationException">Cannot execute a Task that is already running</exception>
+ /// <exception cref="InvalidOperationException">Cannot execute a Task that is already running.</exception>
public async Task Execute(TaskOptions options)
{
var task = Task.Run(async () => await ExecuteInternal(options).ConfigureAwait(false));
@@ -387,11 +395,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
CurrentCancellationTokenSource = new CancellationTokenSource();
- Logger.LogInformation("Executing {0}", Name);
+ _logger.LogInformation("Executing {0}", Name);
- ((TaskManager)TaskManager).OnTaskExecuting(this);
+ ((TaskManager)_taskManager).OnTaskExecuting(this);
- progress.ProgressChanged += progress_ProgressChanged;
+ progress.ProgressChanged += OnProgressChanged;
TaskCompletionStatus status;
CurrentExecutionStartTime = DateTime.UtcNow;
@@ -415,7 +423,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error");
+ _logger.LogError(ex, "Error");
failureException = ex;
@@ -425,7 +433,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
var startTime = CurrentExecutionStartTime;
var endTime = DateTime.UtcNow;
- progress.ProgressChanged -= progress_ProgressChanged;
+ progress.ProgressChanged -= OnProgressChanged;
CurrentCancellationTokenSource.Dispose();
CurrentCancellationTokenSource = null;
CurrentProgress = null;
@@ -438,20 +446,17 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
- void progress_ProgressChanged(object sender, double e)
+ private void OnProgressChanged(object sender, double e)
{
e = Math.Min(e, 100);
CurrentProgress = e;
- TaskProgress?.Invoke(this, new GenericEventArgs<double>
- {
- Argument = e
- });
+ TaskProgress?.Invoke(this, new GenericEventArgs<double>(e));
}
/// <summary>
- /// Stops the task if it is currently executing
+ /// Stops the task if it is currently executing.
/// </summary>
/// <exception cref="InvalidOperationException">Cannot cancel a Task unless it is in the Running state.</exception>
public void Cancel()
@@ -471,7 +476,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
if (State == TaskState.Running)
{
- Logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name);
+ _logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name);
CurrentCancellationTokenSource.Cancel();
}
}
@@ -482,7 +487,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <returns>System.String.</returns>
private string GetScheduledTasksConfigurationDirectory()
{
- return Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
+ return Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
}
/// <summary>
@@ -491,7 +496,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <returns>System.String.</returns>
private string GetScheduledTasksDataDirectory()
{
- return Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
+ return Path.Combine(_applicationPaths.DataPath, "ScheduledTasks");
}
/// <summary>
@@ -530,7 +535,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
TaskTriggerInfo[] list = null;
if (File.Exists(path))
{
- list = JsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path);
+ var bytes = File.ReadAllBytes(path);
+ list = JsonSerializer.Deserialize<TaskTriggerInfo[]>(bytes, _jsonOptions);
}
// Return defaults if file doesn't exist.
@@ -565,8 +571,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
var path = GetConfigurationFilePath();
Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- JsonSerializer.SerializeToFile(triggers, path);
+ using FileStream createStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
+ using Utf8JsonWriter jsonWriter = new Utf8JsonWriter(createStream);
+ JsonSerializer.Serialize(jsonWriter, triggers, _jsonOptions);
}
/// <summary>
@@ -575,11 +582,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="startTime">The start time.</param>
/// <param name="endTime">The end time.</param>
/// <param name="status">The status.</param>
+ /// <param name="ex">The exception.</param>
private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status, Exception ex)
{
var elapsedTime = endTime - startTime;
- Logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
+ _logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
var result = new TaskResult
{
@@ -600,7 +608,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
LastExecutionResult = result;
- ((TaskManager)TaskManager).OnTaskCompleted(this, result);
+ ((TaskManager)_taskManager).OnTaskCompleted(this, result);
}
/// <summary>
@@ -609,6 +617,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
@@ -629,34 +638,35 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
try
{
- Logger.LogInformation(Name + ": Cancelling");
+ _logger.LogInformation(Name + ": Cancelling");
token.Cancel();
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error calling CancellationToken.Cancel();");
+ _logger.LogError(ex, "Error calling CancellationToken.Cancel();");
}
}
+
var task = _currentTask;
if (task != null)
{
try
{
- Logger.LogInformation(Name + ": Waiting on Task");
- var exited = Task.WaitAll(new[] { task }, 2000);
+ _logger.LogInformation(Name + ": Waiting on Task");
+ var exited = task.Wait(2000);
if (exited)
{
- Logger.LogInformation(Name + ": Task exited");
+ _logger.LogInformation(Name + ": Task exited");
}
else
{
- Logger.LogInformation(Name + ": Timed out waiting for task to stop");
+ _logger.LogInformation(Name + ": Timed out waiting for task to stop");
}
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error calling Task.WaitAll();");
+ _logger.LogError(ex, "Error calling Task.WaitAll();");
}
}
@@ -664,14 +674,15 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
try
{
- Logger.LogDebug(Name + ": Disposing CancellationToken");
+ _logger.LogDebug(Name + ": Disposing CancellationToken");
token.Dispose();
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error calling CancellationToken.Dispose();");
+ _logger.LogError(ex, "Error calling CancellationToken.Dispose();");
}
}
+
if (wassRunning)
{
OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null);
@@ -680,12 +691,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger
+ /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger.
/// </summary>
/// <param name="info">The info.</param>
/// <returns>BaseTaskTrigger.</returns>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="ArgumentException">Invalid trigger type: + info.Type</exception>
+ /// <exception cref="ArgumentException">Invalid trigger type: + info.Type.</exception>
private ITaskTrigger GetTrigger(TaskTriggerInfo info)
{
var options = new TaskOptions
@@ -693,21 +703,17 @@ namespace Emby.Server.Implementations.ScheduledTasks
MaxRuntimeTicks = info.MaxRuntimeTicks
};
- if (info.Type.Equals(typeof(DailyTrigger).Name, StringComparison.OrdinalIgnoreCase))
+ if (info.Type.Equals(nameof(DailyTrigger), StringComparison.OrdinalIgnoreCase))
{
if (!info.TimeOfDayTicks.HasValue)
{
throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info));
}
- return new DailyTrigger
- {
- TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
- TaskOptions = options
- };
+ return new DailyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), options);
}
- if (info.Type.Equals(typeof(WeeklyTrigger).Name, StringComparison.OrdinalIgnoreCase))
+ if (info.Type.Equals(nameof(WeeklyTrigger), StringComparison.OrdinalIgnoreCase))
{
if (!info.TimeOfDayTicks.HasValue)
{
@@ -719,45 +725,36 @@ namespace Emby.Server.Implementations.ScheduledTasks
throw new ArgumentException("Info did not contain a DayOfWeek.", nameof(info));
}
- return new WeeklyTrigger
- {
- TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
- DayOfWeek = info.DayOfWeek.Value,
- TaskOptions = options
- };
+ return new WeeklyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), info.DayOfWeek.Value, options);
}
- if (info.Type.Equals(typeof(IntervalTrigger).Name, StringComparison.OrdinalIgnoreCase))
+ if (info.Type.Equals(nameof(IntervalTrigger), StringComparison.OrdinalIgnoreCase))
{
if (!info.IntervalTicks.HasValue)
{
throw new ArgumentException("Info did not contain a IntervalTicks.", nameof(info));
}
- return new IntervalTrigger
- {
- Interval = TimeSpan.FromTicks(info.IntervalTicks.Value),
- TaskOptions = options
- };
+ return new IntervalTrigger(TimeSpan.FromTicks(info.IntervalTicks.Value), options);
}
- if (info.Type.Equals(typeof(StartupTrigger).Name, StringComparison.OrdinalIgnoreCase))
+ if (info.Type.Equals(nameof(StartupTrigger), StringComparison.OrdinalIgnoreCase))
{
- return new StartupTrigger();
+ return new StartupTrigger(options);
}
throw new ArgumentException("Unrecognized trigger type: " + info.Type);
}
/// <summary>
- /// Disposes each trigger
+ /// Disposes each trigger.
/// </summary>
private void DisposeTriggers()
{
foreach (var triggerInfo in InternalTriggers)
{
var trigger = triggerInfo.Item2;
- trigger.Triggered -= trigger_Triggered;
+ trigger.Triggered -= OnTriggerTriggered;
trigger.Stop();
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
index 595c3037d..0431858fc 100644
--- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
@@ -1,84 +1,65 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Jellyfin.Data.Events;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class TaskManager
+ /// Class TaskManager.
/// </summary>
public class TaskManager : ITaskManager
{
- public event EventHandler<GenericEventArgs<IScheduledTaskWorker>> TaskExecuting;
- public event EventHandler<TaskCompletionEventArgs> TaskCompleted;
-
- /// <summary>
- /// Gets the list of Scheduled Tasks
- /// </summary>
- /// <value>The scheduled tasks.</value>
- public IScheduledTaskWorker[] ScheduledTasks { get; private set; }
-
/// <summary>
- /// The _task queue
+ /// The _task queue.
/// </summary>
private readonly ConcurrentQueue<Tuple<Type, TaskOptions>> _taskQueue =
new ConcurrentQueue<Tuple<Type, TaskOptions>>();
- /// <summary>
- /// Gets or sets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- private IJsonSerializer JsonSerializer { get; set; }
-
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <value>The logger.</value>
- private ILogger Logger { get; set; }
- private readonly IFileSystem _fileSystem;
+ private readonly IApplicationPaths _applicationPaths;
+ private readonly ILogger<TaskManager> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="TaskManager" /> class.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="loggerFactory">The logger factory.</param>
- /// <exception cref="System.ArgumentException">kernel</exception>
+ /// <param name="logger">The logger.</param>
public TaskManager(
IApplicationPaths applicationPaths,
- IJsonSerializer jsonSerializer,
- ILoggerFactory loggerFactory,
- IFileSystem fileSystem)
+ ILogger<TaskManager> logger)
{
- ApplicationPaths = applicationPaths;
- JsonSerializer = jsonSerializer;
- Logger = loggerFactory.CreateLogger(nameof(TaskManager));
- _fileSystem = fileSystem;
+ _applicationPaths = applicationPaths;
+ _logger = logger;
- ScheduledTasks = new IScheduledTaskWorker[] { };
+ ScheduledTasks = Array.Empty<IScheduledTaskWorker>();
}
+ public event EventHandler<GenericEventArgs<IScheduledTaskWorker>> TaskExecuting;
+
+ public event EventHandler<TaskCompletionEventArgs> TaskCompleted;
+
+ /// <summary>
+ /// Gets the list of Scheduled Tasks.
+ /// </summary>
+ /// <value>The scheduled tasks.</value>
+ public IScheduledTaskWorker[] ScheduledTasks { get; private set; }
+
/// <summary>
/// Cancels if running and queue.
/// </summary>
- /// <typeparam name="T"></typeparam>
+ /// <typeparam name="T">The task type.</typeparam>
/// <param name="options">Task options.</param>
public void CancelIfRunningAndQueue<T>(TaskOptions options)
- where T : IScheduledTask
+ where T : IScheduledTask
{
var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
((ScheduledTaskWorker)task).CancelIfRunning();
@@ -93,9 +74,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Cancels if running
+ /// Cancels if running.
/// </summary>
- /// <typeparam name="T"></typeparam>
+ /// <typeparam name="T">The task type.</typeparam>
public void CancelIfRunning<T>()
where T : IScheduledTask
{
@@ -106,8 +87,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <summary>
/// Queues the scheduled task.
/// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="options">Task options</param>
+ /// <typeparam name="T">The task type.</typeparam>
+ /// <param name="options">Task options.</param>
public void QueueScheduledTask<T>(TaskOptions options)
where T : IScheduledTask
{
@@ -115,7 +96,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
if (scheduledTask == null)
{
- Logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name);
+ _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name);
}
else
{
@@ -147,13 +128,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
if (scheduledTask == null)
{
- Logger.LogError("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name);
+ _logger.LogError("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name);
}
else
{
var type = scheduledTask.ScheduledTask.GetType();
- Logger.LogInformation("Queueing task {0}", type.Name);
+ _logger.LogInformation("Queuing task {0}", type.Name);
lock (_taskQueue)
{
@@ -176,7 +157,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
if (scheduledTask == null)
{
- Logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name);
+ _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name);
}
else
{
@@ -193,7 +174,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
var type = task.ScheduledTask.GetType();
- Logger.LogInformation("Queueing task {0}", type.Name);
+ _logger.LogInformation("Queuing task {0}", type.Name);
lock (_taskQueue)
{
@@ -213,7 +194,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="tasks">The tasks.</param>
public void AddTasks(IEnumerable<IScheduledTask> tasks)
{
- var list = tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem));
+ var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _logger));
ScheduledTasks = ScheduledTasks.Concat(list).ToArray();
}
@@ -224,6 +205,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
@@ -254,10 +236,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="task">The task.</param>
internal void OnTaskExecuting(IScheduledTaskWorker task)
{
- TaskExecuting?.Invoke(this, new GenericEventArgs<IScheduledTaskWorker>
- {
- Argument = task
- });
+ TaskExecuting?.Invoke(this, new GenericEventArgs<IScheduledTaskWorker>(task));
}
/// <summary>
@@ -267,11 +246,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="result">The result.</param>
internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result)
{
- TaskCompleted?.Invoke(task, new TaskCompletionEventArgs
- {
- Result = result,
- Task = task
- });
+ TaskCompleted?.Invoke(task, new TaskCompletionEventArgs(task, result));
ExecuteQueuedTasks();
}
@@ -281,7 +256,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
private void ExecuteQueuedTasks()
{
- Logger.LogInformation("ExecuteQueuedTasks");
+ _logger.LogInformation("ExecuteQueuedTasks");
// Execute queued tasks
lock (_taskQueue)
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index 2f07ff15a..09ea6271d 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -12,23 +12,19 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
-using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class ChapterImagesTask
+ /// Class ChapterImagesTask.
/// </summary>
public class ChapterImagesTask : IScheduledTask
{
/// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _library manager
+ /// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
@@ -38,27 +34,50 @@ namespace Emby.Server.Implementations.ScheduledTasks
private readonly IEncodingManager _encodingManager;
private readonly IFileSystem _fileSystem;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
/// </summary>
- public ChapterImagesTask(ILoggerFactory loggerFactory, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager, IFileSystem fileSystem)
+ /// <param name="libraryManager">The library manager.</param>.
+ /// <param name="itemRepo">The item repository.</param>
+ /// <param name="appPaths">The application paths.</param>
+ /// <param name="encodingManager">The encoding manager.</param>
+ /// <param name="fileSystem">The filesystem.</param>
+ /// <param name="localization">The localization manager.</param>
+ public ChapterImagesTask(
+ ILibraryManager libraryManager,
+ IItemRepository itemRepo,
+ IApplicationPaths appPaths,
+ IEncodingManager encodingManager,
+ IFileSystem fileSystem,
+ ILocalizationManager localization)
{
- _logger = loggerFactory.CreateLogger(GetType().Name);
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_appPaths = appPaths;
_encodingManager = encodingManager;
_fileSystem = fileSystem;
+ _localization = localization;
}
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
+
+ /// <inheritdoc />
+ public string Key => "RefreshChapterImages";
+
+ /// <inheritdoc />
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
- return new[] {
-
+ return new[]
+ {
new TaskTriggerInfo
{
Type = TaskTriggerInfo.TriggerDaily,
@@ -69,7 +88,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Returns the task to be executed
+ /// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
@@ -88,7 +107,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
SourceTypes = new SourceType[] { SourceType.Library },
HasChapterImages = false,
IsVirtualItem = false
-
})
.OfType<Video>()
.ToList();
@@ -104,7 +122,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
try
{
previouslyFailedImages = File.ReadAllText(failHistoryPath)
- .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
+ .Split('|', StringSplitOptions.RemoveEmptyEntries)
.ToList();
}
catch (IOException)
@@ -117,7 +135,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
previouslyFailedImages = new List<string>();
}
- var directoryService = new DirectoryService(_logger, _fileSystem);
+ var directoryService = new DirectoryService(_fileSystem);
foreach (var video in videos)
{
@@ -138,10 +156,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
previouslyFailedImages.Add(key);
var parentPath = Path.GetDirectoryName(failHistoryPath);
+ if (parentPath != null)
+ {
+ Directory.CreateDirectory(parentPath);
+ }
- Directory.CreateDirectory(parentPath);
-
- string text = string.Join("|", previouslyFailedImages);
+ string text = string.Join('|', previouslyFailedImages);
File.WriteAllText(failHistoryPath, text);
}
@@ -153,24 +173,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
catch (ObjectDisposedException)
{
- //TODO Investigate and properly fix.
+ // TODO Investigate and properly fix.
break;
}
}
}
-
- public string Name => "Chapter image extraction";
-
- public string Description => "Creates thumbnails for videos that have chapters.";
-
- public string Category => "Library";
-
- public string Key => "RefreshChapterImages";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
new file mode 100644
index 000000000..79886cb52
--- /dev/null
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Tasks;
+
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Deletes old activity log entries.
+ /// </summary>
+ public class CleanActivityLogTask : IScheduledTask, IConfigurableScheduledTask
+ {
+ private readonly ILocalizationManager _localization;
+ private readonly IActivityManager _activityManager;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CleanActivityLogTask"/> class.
+ /// </summary>
+ /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
+ /// <param name="activityManager">Instance of the <see cref="IActivityManager"/> interface.</param>
+ /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
+ public CleanActivityLogTask(
+ ILocalizationManager localization,
+ IActivityManager activityManager,
+ IServerConfigurationManager serverConfigurationManager)
+ {
+ _localization = localization;
+ _activityManager = activityManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
+
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskCleanActivityLog");
+
+ /// <inheritdoc />
+ public string Key => "CleanActivityLog";
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskCleanActivityLogDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
+ /// <inheritdoc />
+ public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
+ if (!retentionDays.HasValue || retentionDays < 0)
+ {
+ throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
+ }
+
+ var startDate = DateTime.UtcNow.AddDays(-retentionDays.Value);
+ return _activityManager.CleanAsync(startDate);
+ }
+
+ /// <inheritdoc />
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return Enumerable.Empty<TaskTriggerInfo>();
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 6ec83b5c0..a575b260c 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
@@ -12,7 +13,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
- /// Deletes old cache files
+ /// Deletes old cache files.
/// </summary>
public class DeleteCacheFileTask : IScheduledTask, IConfigurableScheduledTask
{
@@ -20,37 +21,66 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// Gets or sets the application paths.
/// </summary>
/// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
-
- private readonly ILogger _logger;
-
+ private readonly IApplicationPaths _applicationPaths;
+ private readonly ILogger<DeleteCacheFileTask> _logger;
private readonly IFileSystem _fileSystem;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
/// </summary>
- public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
+ /// <param name="appPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
+ /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
+ /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
+ /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
+ public DeleteCacheFileTask(
+ IApplicationPaths appPaths,
+ ILogger<DeleteCacheFileTask> logger,
+ IFileSystem fileSystem,
+ ILocalizationManager localization)
{
- ApplicationPaths = appPaths;
+ _applicationPaths = appPaths;
_logger = logger;
_fileSystem = fileSystem;
+ _localization = localization;
}
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskCleanCache");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ /// <inheritdoc />
+ public string Key => "DeleteCacheFiles";
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
- return new[] {
-
+ return new[]
+ {
// Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
+ new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
};
}
/// <summary>
- /// Returns the task to be executed
+ /// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
@@ -61,7 +91,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.CachePath, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.CachePath, minDateModified, progress);
}
catch (DirectoryNotFoundException)
{
@@ -74,7 +104,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.TempDirectory, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.TempDirectory, minDateModified, progress);
}
catch (DirectoryNotFoundException)
{
@@ -84,9 +114,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
return Task.CompletedTask;
}
-
/// <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>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
@@ -157,19 +186,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
_logger.LogError(ex, "Error deleting file {path}", path);
}
}
-
- public string Name => "Cache file cleanup";
-
- public string Description => "Deletes cache files no longer needed by the system";
-
- public string Category => "Maintenance";
-
- public string Key => "DeleteCacheFiles";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index e468c301a..fedb5deb0 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -1,52 +1,76 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
- /// Deletes old log files
+ /// Deletes old log files.
/// </summary>
public class DeleteLogFileTask : IScheduledTask, IConfigurableScheduledTask
{
- /// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private IConfigurationManager ConfigurationManager { get; set; }
-
+ private readonly IConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
/// </summary>
/// <param name="configurationManager">The configuration manager.</param>
- public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem)
+ /// <param name="fileSystem">The file system.</param>
+ /// <param name="localization">The localization manager.</param>
+ public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization)
{
- ConfigurationManager = configurationManager;
+ _configurationManager = configurationManager;
_fileSystem = fileSystem;
+ _localization = localization;
}
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskCleanLogs");
+
+ /// <inheritdoc />
+ public string Description => string.Format(
+ CultureInfo.InvariantCulture,
+ _localization.GetLocalizedString("TaskCleanLogsDescription"),
+ _configurationManager.CommonConfiguration.LogFileRetentionDays);
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ /// <inheritdoc />
+ public string Key => "CleanLogFiles";
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
+ return new[]
+ {
+ new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
};
}
/// <summary>
- /// Returns the task to be executed
+ /// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
@@ -54,12 +78,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
// Delete log files more than n days old
- var minDateModified = DateTime.UtcNow.AddDays(-ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
+ var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays);
- // Only delete the .txt log files, the *.log files created by serilog get managed by itself
- var filesToDelete = _fileSystem.GetFiles(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, new[] { ".txt" }, true, true)
- .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
- .ToList();
+ // Only delete files that serilog doesn't manage (anything that doesn't start with 'log_'
+ var filesToDelete = _fileSystem.GetFiles(_configurationManager.CommonApplicationPaths.LogDirectoryPath, true)
+ .Where(f => !f.Name.StartsWith("log_", StringComparison.Ordinal)
+ && _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
+ .ToList();
var index = 0;
@@ -80,19 +105,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
return Task.CompletedTask;
}
-
- public string Name => "Log file cleanup";
-
- public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
-
- public string Category => "Maintenance";
-
- public string Key => "CleanLogFiles";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
new file mode 100644
index 000000000..b13fc7fc6
--- /dev/null
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
@@ -0,0 +1,170 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Deletes all transcoding temp files.
+ /// </summary>
+ public class DeleteTranscodeFileTask : IScheduledTask, IConfigurableScheduledTask
+ {
+ private readonly ILogger<DeleteTranscodeFileTask> _logger;
+ private readonly IConfigurationManager _configurationManager;
+ private readonly IFileSystem _fileSystem;
+ private readonly ILocalizationManager _localization;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DeleteTranscodeFileTask"/> class.
+ /// </summary>
+ /// <param name="logger">Instance of the <see cref="ILogger{DeleteTranscodeFileTask}"/> interface.</param>
+ /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
+ /// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param>
+ /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
+ public DeleteTranscodeFileTask(
+ ILogger<DeleteTranscodeFileTask> logger,
+ IFileSystem fileSystem,
+ IConfigurationManager configurationManager,
+ ILocalizationManager localization)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+ _configurationManager = configurationManager;
+ _localization = localization;
+ }
+
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskCleanTranscode");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskCleanTranscodeDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ /// <inheritdoc />
+ public string Key => "DeleteTranscodeFiles";
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run.
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return new[]
+ {
+ new TaskTriggerInfo
+ {
+ Type = TaskTriggerInfo.TriggerInterval,
+ IntervalTicks = TimeSpan.FromHours(24).Ticks
+ }
+ };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed.
+ /// </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);
+ progress.Report(50);
+
+ DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodePath(), minDateModified, progress);
+
+ return Task.CompletedTask;
+ }
+
+ /// <summary>
+ /// Deletes the transcoded temp files from directory with a last write time less than a given date.
+ /// </summary>
+ /// <param name="cancellationToken">The task cancellation token.</param>
+ /// <param name="directory">The directory.</param>
+ /// <param name="minDateModified">The min date modified.</param>
+ /// <param name="progress">The progress.</param>
+ private void DeleteTempFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
+ {
+ var filesToDelete = _fileSystem.GetFiles(directory, true)
+ .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
+ .ToList();
+
+ var index = 0;
+
+ foreach (var file in filesToDelete)
+ {
+ double percent = index;
+ percent /= filesToDelete.Count;
+
+ progress.Report(100 * percent);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ DeleteFile(file.FullName);
+
+ index++;
+ }
+
+ DeleteEmptyFolders(directory);
+
+ progress.Report(100);
+ }
+
+ private void DeleteEmptyFolders(string parent)
+ {
+ foreach (var directory in _fileSystem.GetDirectoryPaths(parent))
+ {
+ DeleteEmptyFolders(directory);
+ if (!_fileSystem.GetFileSystemEntryPaths(directory).Any())
+ {
+ try
+ {
+ Directory.Delete(directory, false);
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ _logger.LogError(ex, "Error deleting directory {path}", directory);
+ }
+ catch (IOException ex)
+ {
+ _logger.LogError(ex, "Error deleting directory {path}", directory);
+ }
+ }
+ }
+ }
+
+ private void DeleteFile(string path)
+ {
+ try
+ {
+ _fileSystem.DeleteFile(path);
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ _logger.LogError(ex, "Error deleting file {path}", path);
+ }
+ catch (IOException ex)
+ {
+ _logger.LogError(ex, "Error deleting file {path}", path);
+ }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
new file mode 100644
index 000000000..35a4aeef6
--- /dev/null
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Server.Implementations;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Optimizes Jellyfin's database by issuing a VACUUM command.
+ /// </summary>
+ public class OptimizeDatabaseTask : IScheduledTask, IConfigurableScheduledTask
+ {
+ private readonly ILogger<OptimizeDatabaseTask> _logger;
+ private readonly ILocalizationManager _localization;
+ private readonly JellyfinDbProvider _provider;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OptimizeDatabaseTask" /> class.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ /// <param name="localization">The localization manager.</param>
+ /// <param name="provider">The jellyfin DB context provider.</param>
+ public OptimizeDatabaseTask(
+ ILogger<OptimizeDatabaseTask> logger,
+ ILocalizationManager localization,
+ JellyfinDbProvider provider)
+ {
+ _logger = logger;
+ _localization = localization;
+ _provider = provider;
+ }
+
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskOptimizeDatabase");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskOptimizeDatabaseDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ /// <inheritdoc />
+ public string Key => "OptimizeDatabaseTask";
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run.
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return new[]
+ {
+ // Every so often
+ new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks }
+ };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed.
+ /// </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...");
+
+ try
+ {
+ using var context = _provider.CreateContext();
+ if (context.Database.IsSqlite())
+ {
+ context.Database.ExecuteSqlRaw("PRAGMA optimize");
+ context.Database.ExecuteSqlRaw("VACUUM");
+ _logger.LogInformation("jellyfin.db optimized successfully!");
+ }
+ else
+ {
+ _logger.LogInformation("This database doesn't support optimization");
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Error while optimizing jellyfin.db");
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
index d70799c47..53c692a46 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
@@ -1,44 +1,59 @@
+#pragma warning disable CS1591
+
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Controller;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class PeopleValidationTask
+ /// Class PeopleValidationTask.
/// </summary>
public class PeopleValidationTask : IScheduledTask
{
/// <summary>
- /// The _library manager
+ /// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
-
- private readonly IServerApplicationHost _appHost;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
- /// <param name="appHost">The server application host</param>
- public PeopleValidationTask(ILibraryManager libraryManager, IServerApplicationHost appHost)
+ /// <param name="localization">The localization manager.</param>
+ public PeopleValidationTask(ILibraryManager libraryManager, ILocalizationManager localization)
{
_libraryManager = libraryManager;
- _appHost = appHost;
+ _localization = localization;
}
+ public string Name => _localization.GetLocalizedString("TaskRefreshPeople");
+
+ public string Description => _localization.GetLocalizedString("TaskRefreshPeopleDescription");
+
+ public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
+
+ public string Key => "RefreshPeople";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
+
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
+ /// <returns>An <see cref="IEnumerable{TaskTriggerInfo}"/> containing the default trigger infos for this task.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
return new[]
{
- // Every so often
new TaskTriggerInfo
{
Type = TaskTriggerInfo.TriggerInterval,
@@ -48,7 +63,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Returns the task to be executed
+ /// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
@@ -57,19 +72,5 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
return _libraryManager.ValidatePeople(cancellationToken, progress);
}
-
- public string Name => "Refresh people";
-
- public string Description => "Updates metadata for actors and directors in your media library.";
-
- public string Category => "Library";
-
- public string Key => "RefreshPeople";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
index c6431c311..11a5fb79f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -1,66 +1,85 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Model.Net;
+#pragma warning disable CS1591
+
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Plugin Update Task
+ /// Plugin Update Task.
/// </summary>
public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
{
/// <summary>
- /// The _logger
+ /// The _logger.
/// </summary>
- private readonly ILogger _logger;
+ private readonly ILogger<PluginUpdateTask> _logger;
private readonly IInstallationManager _installationManager;
+ private readonly ILocalizationManager _localization;
- private readonly IApplicationHost _appHost;
-
- public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
+ public PluginUpdateTask(ILogger<PluginUpdateTask> logger, IInstallationManager installationManager, ILocalizationManager localization)
{
_logger = logger;
_installationManager = installationManager;
- _appHost = appHost;
+ _localization = localization;
}
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskUpdatePlugins");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksApplicationCategory");
+
+ /// <inheritdoc />
+ public string Key => "PluginUpdates";
+
+ /// <inheritdoc />
+ public bool IsHidden => false;
+
+ /// <inheritdoc />
+ public bool IsEnabled => true;
+
+ /// <inheritdoc />
+ public bool IsLogged => true;
+
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
- return new[] {
-
- // At startup
- new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
- };
+ // At startup
+ yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerStartup };
+
+ // Every so often
+ yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks };
}
/// <summary>
- /// Update installed plugins
+ /// Update installed plugins.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
+ /// <returns><see cref="Task" />.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
progress.Report(0);
- var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList();
+ var packageFetchTask = _installationManager.GetAvailablePluginUpdates(cancellationToken);
+ var packagesToInstall = (await packageFetchTask.ConfigureAwait(false)).ToList();
progress.Report(10);
@@ -72,7 +91,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
try
{
- await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
+ await _installationManager.InstallPackage(package, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -82,38 +101,23 @@ namespace Emby.Server.Implementations.ScheduledTasks
throw;
}
}
- catch (HttpException ex)
+ catch (HttpRequestException ex)
{
- _logger.LogError(ex, "Error downloading {0}", package.name);
+ _logger.LogError(ex, "Error downloading {0}", package.Name);
}
catch (IOException ex)
{
- _logger.LogError(ex, "Error updating {0}", package.name);
+ _logger.LogError(ex, "Error updating {0}", package.Name);
}
// Update progress
lock (progress)
{
- numComplete++;
- progress.Report(90.0 * numComplete / packagesToInstall.Count + 10);
+ progress.Report((90.0 * ++numComplete / packagesToInstall.Count) + 10);
}
}
progress.Report(100);
}
-
- public string Name => "Check for plugin updates";
-
- public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
-
- public string Category => "Application";
-
- public string Key => "PluginUpdates";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
index 1a3d85ad7..2184b3d03 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
@@ -1,45 +1,60 @@
+#pragma warning disable CS1591
+
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Library;
-using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class RefreshMediaLibraryTask
+ /// Class RefreshMediaLibraryTask.
/// </summary>
public class RefreshMediaLibraryTask : IScheduledTask
{
/// <summary>
- /// The _library manager
+ /// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
- public RefreshMediaLibraryTask(ILibraryManager libraryManager, IServerConfigurationManager config)
+ /// <param name="localization">The localization manager.</param>
+ public RefreshMediaLibraryTask(ILibraryManager libraryManager, ILocalizationManager localization)
{
_libraryManager = libraryManager;
- _config = config;
+ _localization = localization;
}
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskRefreshLibrary");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskRefreshLibraryDescription");
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
+
+ /// <inheritdoc />
+ public string Key => "RefreshLibrary";
+
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(12).Ticks}
+ yield return new TaskTriggerInfo
+ {
+ Type = TaskTriggerInfo.TriggerInterval,
+ IntervalTicks = TimeSpan.FromHours(12).Ticks
};
}
@@ -57,19 +72,5 @@ namespace Emby.Server.Implementations.ScheduledTasks
return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
}
-
- public string Name => "Scan media library";
-
- public string Description => "Scans your media library and refreshes metatata based on configuration.";
-
- public string Category => "Library";
-
- public string Key => "RefreshLibrary";
-
- public bool IsHidden => false;
-
- public bool IsEnabled => true;
-
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index 98685cebe..29ab6a73d 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
@@ -1,5 +1,4 @@
using System;
-using System.Globalization;
using System.Threading;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
@@ -7,31 +6,40 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Represents a task trigger that fires everyday
+ /// Represents a task trigger that fires everyday.
/// </summary>
- public class DailyTrigger : ITaskTrigger
+ public sealed class DailyTrigger : ITaskTrigger
{
+ private readonly TimeSpan _timeOfDay;
+ private Timer? _timer;
+
/// <summary>
- /// Get the time of day to trigger the task to run
+ /// Initializes a new instance of the <see cref="DailyTrigger"/> class.
/// </summary>
- /// <value>The time of day.</value>
- public TimeSpan TimeOfDay { get; set; }
+ /// <param name="timeofDay">The time of day to trigger the task to run.</param>
+ /// <param name="taskOptions">The options of this task.</param>
+ public DailyTrigger(TimeSpan timeofDay, TaskOptions taskOptions)
+ {
+ _timeOfDay = timeofDay;
+ TaskOptions = taskOptions;
+ }
/// <summary>
- /// Gets or sets the options of this task.
+ /// Occurs when [triggered].
/// </summary>
- public TaskOptions TaskOptions { get; set; }
+ public event EventHandler<EventArgs>? Triggered;
/// <summary>
- /// Gets or sets the timer.
+ /// Gets the options of this task.
/// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
+ public TaskOptions TaskOptions { get; }
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="taskName">The name of the task.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
@@ -39,18 +47,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
var now = DateTime.Now;
- var triggerDate = now.TimeOfDay > TimeOfDay ? now.Date.AddDays(1) : now.Date;
- triggerDate = triggerDate.Add(TimeOfDay);
+ var triggerDate = now.TimeOfDay > _timeOfDay ? now.Date.AddDays(1) : now.Date;
+ triggerDate = triggerDate.Add(_timeOfDay);
var dueTime = triggerDate - now;
- logger.LogInformation("Daily trigger for {0} set to fire at {1}, which is {2} minutes from now.", taskName, triggerDate.ToString(), dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
+ logger.LogInformation("Daily trigger for {Task} set to fire at {TriggerDate:yyyy-MM-dd HH:mm:ss.fff zzz}, which is {DueTime:c} from now.", taskName, triggerDate, dueTime);
- Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
+ _timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
@@ -62,26 +70,15 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
private void DisposeTimer()
{
- if (Timer != null)
- {
- Timer.Dispose();
- }
+ _timer?.Dispose();
}
/// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<EventArgs> Triggered;
-
- /// <summary>
/// Called when [triggered].
/// </summary>
private void OnTriggered()
{
- if (Triggered != null)
- {
- Triggered(this, EventArgs.Empty);
- }
+ Triggered?.Invoke(this, EventArgs.Empty);
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index 3a34da3af..30568e809 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
@@ -7,33 +7,41 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Represents a task trigger that runs repeatedly on an interval
+ /// Represents a task trigger that runs repeatedly on an interval.
/// </summary>
- public class IntervalTrigger : ITaskTrigger
+ public sealed class IntervalTrigger : ITaskTrigger
{
+ private readonly TimeSpan _interval;
+ private DateTime _lastStartDate;
+ private Timer? _timer;
+
/// <summary>
- /// Gets or sets the interval.
+ /// Initializes a new instance of the <see cref="IntervalTrigger"/> class.
/// </summary>
- /// <value>The interval.</value>
- public TimeSpan Interval { get; set; }
+ /// <param name="interval">The interval.</param>
+ /// <param name="taskOptions">The options of this task.</param>
+ public IntervalTrigger(TimeSpan interval, TaskOptions taskOptions)
+ {
+ _interval = interval;
+ TaskOptions = taskOptions;
+ }
/// <summary>
- /// Gets or sets the options of this task.
+ /// Occurs when [triggered].
/// </summary>
- public TaskOptions TaskOptions { get; set; }
+ public event EventHandler<EventArgs>? Triggered;
/// <summary>
- /// Gets or sets the timer.
+ /// Gets the options of this task.
/// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
-
- private DateTime _lastStartDate;
+ public TaskOptions TaskOptions { get; }
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="taskName">The name of the task.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
@@ -48,7 +56,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
else
{
- triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(Interval);
+ triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(_interval);
}
if (DateTime.UtcNow > triggerDate)
@@ -64,11 +72,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
dueTime = maxDueTime;
}
- Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
+ _timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
@@ -80,18 +88,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
private void DisposeTimer()
{
- if (Timer != null)
- {
- Timer.Dispose();
- }
+ _timer?.Dispose();
}
/// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<EventArgs> Triggered;
-
- /// <summary>
/// Called when [triggered].
/// </summary>
private void OnTriggered()
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
index 08ff4f55f..18b9a8b75 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
using System;
using System.Threading.Tasks;
using MediaBrowser.Model.Tasks;
@@ -6,26 +8,37 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class StartupTaskTrigger
+ /// Class StartupTaskTrigger.
/// </summary>
- public class StartupTrigger : ITaskTrigger
+ public sealed class StartupTrigger : ITaskTrigger
{
- public int DelayMs { get; set; }
+ public const int DelayMs = 3000;
/// <summary>
- /// Gets or sets the options of this task.
+ /// Initializes a new instance of the <see cref="StartupTrigger"/> class.
/// </summary>
- public TaskOptions TaskOptions { get; set; }
-
- public StartupTrigger()
+ /// <param name="taskOptions">The options of this task.</param>
+ public StartupTrigger(TaskOptions taskOptions)
{
- DelayMs = 3000;
+ TaskOptions = taskOptions;
}
/// <summary>
- /// Stars waiting for the trigger action
+ /// Occurs when [triggered].
+ /// </summary>
+ public event EventHandler<EventArgs>? Triggered;
+
+ /// <summary>
+ /// Gets the options of this task.
+ /// </summary>
+ public TaskOptions TaskOptions { get; }
+
+ /// <summary>
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="taskName">The name of the task.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
public async void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
@@ -38,26 +51,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
}
/// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<EventArgs> Triggered;
-
- /// <summary>
/// Called when [triggered].
/// </summary>
private void OnTriggered()
{
- if (Triggered != null)
- {
- Triggered(this, EventArgs.Empty);
- }
+ Triggered?.Invoke(this, EventArgs.Empty);
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index 2a6a7b13c..36ae190b0 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
@@ -6,37 +6,43 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Represents a task trigger that fires on a weekly basis
+ /// Represents a task trigger that fires on a weekly basis.
/// </summary>
- public class WeeklyTrigger : ITaskTrigger
+ public sealed class WeeklyTrigger : ITaskTrigger
{
- /// <summary>
- /// Get the time of day to trigger the task to run
- /// </summary>
- /// <value>The time of day.</value>
- public TimeSpan TimeOfDay { get; set; }
+ private readonly TimeSpan _timeOfDay;
+ private readonly DayOfWeek _dayOfWeek;
+ private Timer? _timer;
/// <summary>
- /// Gets or sets the day of week.
+ /// Initializes a new instance of the <see cref="WeeklyTrigger"/> class.
/// </summary>
- /// <value>The day of week.</value>
- public DayOfWeek DayOfWeek { get; set; }
+ /// <param name="timeofDay">The time of day to trigger the task to run.</param>
+ /// <param name="dayOfWeek">The day of week.</param>
+ /// <param name="taskOptions">The options of this task.</param>
+ public WeeklyTrigger(TimeSpan timeofDay, DayOfWeek dayOfWeek, TaskOptions taskOptions)
+ {
+ _timeOfDay = timeofDay;
+ _dayOfWeek = dayOfWeek;
+ TaskOptions = taskOptions;
+ }
/// <summary>
- /// Gets or sets the options of this task.
+ /// Occurs when [triggered].
/// </summary>
- public TaskOptions TaskOptions { get; set; }
+ public event EventHandler<EventArgs>? Triggered;
/// <summary>
- /// Gets or sets the timer.
+ /// Gets the options of this task.
/// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
+ public TaskOptions TaskOptions { get; }
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="taskName">The name of the task.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
@@ -44,7 +50,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
var triggerDate = GetNextTriggerDateTime();
- Timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.Now, TimeSpan.FromMilliseconds(-1));
+ _timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.Now, TimeSpan.FromMilliseconds(-1));
}
/// <summary>
@@ -56,26 +62,26 @@ namespace Emby.Server.Implementations.ScheduledTasks
var now = DateTime.Now;
// If it's on the same day
- if (now.DayOfWeek == DayOfWeek)
+ if (now.DayOfWeek == _dayOfWeek)
{
// It's either later today, or a week from now
- return now.TimeOfDay < TimeOfDay ? now.Date.Add(TimeOfDay) : now.Date.AddDays(7).Add(TimeOfDay);
+ return now.TimeOfDay < _timeOfDay ? now.Date.Add(_timeOfDay) : now.Date.AddDays(7).Add(_timeOfDay);
}
var triggerDate = now.Date;
// Walk the date forward until we get to the trigger day
- while (triggerDate.DayOfWeek != DayOfWeek)
+ while (triggerDate.DayOfWeek != _dayOfWeek)
{
triggerDate = triggerDate.AddDays(1);
}
// Return the trigger date plus the time offset
- return triggerDate.Add(TimeOfDay);
+ return triggerDate.Add(_timeOfDay);
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
@@ -87,26 +93,15 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </summary>
private void DisposeTimer()
{
- if (Timer != null)
- {
- Timer.Dispose();
- }
+ _timer?.Dispose();
}
/// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<EventArgs> Triggered;
-
- /// <summary>
/// Called when [triggered].
/// </summary>
private void OnTriggered()
{
- if (Triggered != null)
- {
- Triggered(this, EventArgs.Empty);
- }
+ Triggered?.Invoke(this, EventArgs.Empty);
}
}
}