mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Reworking the task manager & using unity containers
This commit is contained in:
parent
0221cb7873
commit
b7294114b9
39
Kyoo.Common/Controllers/IPlugin.cs
Normal file
39
Kyoo.Common/Controllers/IPlugin.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A common interface used to discord plugins
|
||||||
|
/// </summary>
|
||||||
|
public interface IPlugin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A slug to identify this plugin in queries.
|
||||||
|
/// </summary>
|
||||||
|
string Slug { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the plugin
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The description of this plugin. This will be displayed on the "installed plugins" page.
|
||||||
|
/// </summary>
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A configure method that will be runned on plugin's startup.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You can have use any services as parameter, they will be injected from the service provider
|
||||||
|
/// You can add managed types or any type you like using the IUnityContainer like so:
|
||||||
|
/// <code>
|
||||||
|
/// public static void Configure(IUnityContainer services)
|
||||||
|
/// {
|
||||||
|
/// services.AddTask<MyTask>()
|
||||||
|
/// }
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
static void Configure() { }
|
||||||
|
}
|
||||||
|
}
|
188
Kyoo.Common/Controllers/ITask.cs
Normal file
188
Kyoo.Common/Controllers/ITask.cs
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Models.Attributes;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A single task parameter. This struct contains metadata to display and utility functions to get them in the taks.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This struct will be used to generate the swagger documentation of the task.</remarks>
|
||||||
|
public record TaskParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of this parameter.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The description of this parameter.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of this parameter.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this parameter required or can it be ignored?
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRequired { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default value of this object.
|
||||||
|
/// </summary>
|
||||||
|
public object DefaultValue { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value of the parameter.
|
||||||
|
/// </summary>
|
||||||
|
private object Value { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new task parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the parameter</param>
|
||||||
|
/// <param name="description">The description of the parameter</param>
|
||||||
|
/// <typeparam name="T">The type of the parameter.</typeparam>
|
||||||
|
/// <returns>A new task parameter.</returns>
|
||||||
|
public static TaskParameter Create<T>(string name, string description)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Description = description,
|
||||||
|
Type = typeof(T)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a parameter's value to give to a task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the parameter</param>
|
||||||
|
/// <param name="value">The value of the parameter. It's type will be used as parameter's type.</param>
|
||||||
|
/// <typeparam name="T">The type of the parameter</typeparam>
|
||||||
|
/// <returns>A TaskParameter that can be used as value.</returns>
|
||||||
|
public static TaskParameter CreateValue<T>(string name, T value)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Type = typeof(T),
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a parameter's value for the current parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to use</param>
|
||||||
|
/// <returns>A new parameter's value for this current parameter</returns>
|
||||||
|
public TaskParameter CreateValue(object value)
|
||||||
|
{
|
||||||
|
return this with {Value = value};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the value of this parameter. If the value is of the wrong type, it will be converted.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of this parameter</typeparam>
|
||||||
|
/// <returns>The value of this parameter.</returns>
|
||||||
|
public T As<T>()
|
||||||
|
{
|
||||||
|
return (T)Convert.ChangeType(Value, typeof(T));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A parameters container implementing an indexer to allow simple usage of parameters.
|
||||||
|
/// </summary>
|
||||||
|
public class TaskParameters : List<TaskParameter>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An indexer that return the parameter with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the task (case sensitive)</param>
|
||||||
|
public TaskParameter this[string name] => this.FirstOrDefault(x => x.Name == name);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new, empty, <see cref="TaskParameters"/>
|
||||||
|
/// </summary>
|
||||||
|
public TaskParameters() {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="TaskParameters"/> with an initial parameters content
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">The list of parameters</param>
|
||||||
|
public TaskParameters(IEnumerable<TaskParameter> parameters)
|
||||||
|
{
|
||||||
|
AddRange(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A common interface that tasks should implement.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The slug of the task, used to start it.
|
||||||
|
/// </summary>
|
||||||
|
public string Slug { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the task that will be displayed to the user.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A quick description of what this task will do.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An optional message to display to help the user.
|
||||||
|
/// </summary>
|
||||||
|
public string HelpMessage { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should this task be automatically runned at app startup?
|
||||||
|
/// </summary>
|
||||||
|
public bool RunOnStartup { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The priority of this task. Only used if <see cref="RunOnStartup"/> is true.
|
||||||
|
/// It allow one to specify witch task will be started first as tasked are run on a Priority's descending order.
|
||||||
|
/// </summary>
|
||||||
|
public int Priority { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start this task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="arguments">The list of parameters.</param>
|
||||||
|
/// <param name="cancellationToken">A token to request the task's cancelation.
|
||||||
|
/// If this task is not cancelled quickly, it might be killed by the runner.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Your task can have any service as a public field and use the <see cref="InjectedAttribute"/>,
|
||||||
|
/// they will be set to an available service from the service container before calling this method.
|
||||||
|
/// </remarks>
|
||||||
|
public Task Run(TaskParameters arguments, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of parameters
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>All parameters that this task as. Every one of them will be given to the run function with a value.</returns>
|
||||||
|
public TaskParameters GetParameters();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this task is running, return the percentage of completion of this task or null if no percentage can be given.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The percentage of completion of the task.</returns>
|
||||||
|
public int? Progress();
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,40 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A service to handle long running tasks.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The concurrent number of running tasks is implementation dependent.</remarks>
|
||||||
public interface ITaskManager
|
public interface ITaskManager
|
||||||
{
|
{
|
||||||
bool StartTask(string taskSlug, string arguments = null);
|
/// <summary>
|
||||||
ITask GetRunningTask();
|
/// Start a new task (or queue it).
|
||||||
void ReloadTask();
|
/// </summary>
|
||||||
IEnumerable<ITask> GetAllTasks();
|
/// <param name="taskSlug">The slug of the task to run</param>
|
||||||
|
/// <param name="arguments">A list of arguments to pass to the task. An automatic conversion will be made if arguments to not fit.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the number of arguments is invalid or if an argument can't be converted.</exception>
|
||||||
|
/// <exception cref="ItemNotFound">The task could not be found.</exception>
|
||||||
|
void StartTask(string taskSlug, Dictionary<string, object> arguments);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all currently running tasks
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of currently running tasks.</returns>
|
||||||
|
ICollection<ITask> GetRunningTasks();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all availables tasks
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of every tasks that this instance know.</returns>
|
||||||
|
ICollection<ITask> GetAllTasks();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reload tasks and run startup tasks.
|
||||||
|
/// </summary>
|
||||||
|
void ReloadTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,6 +24,13 @@
|
|||||||
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="Unity.Abstractions" Version="5.11.7" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
|
||||||
|
<HintPath>..\..\..\..\..\..\usr\share\dotnet\shared\Microsoft.AspNetCore.App\5.0.5\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
14
Kyoo.Common/Models/Attributes/InjectedAttribute.cs
Normal file
14
Kyoo.Common/Models/Attributes/InjectedAttribute.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
|
||||||
|
namespace Kyoo.Models.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An attribute to inform that the service will be injected automatically by a service provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It should only be used on <see cref="ITask"/> and will be injected before calling <see cref="ITask.Run"/>
|
||||||
|
/// </remarks>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class InjectedAttribute : Attribute { }
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Kyoo.Models
|
|
||||||
{
|
|
||||||
public interface IPlugin
|
|
||||||
{
|
|
||||||
public string Name { get; }
|
|
||||||
public ICollection<ITask> Tasks { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Kyoo.Models
|
|
||||||
{
|
|
||||||
public interface ITask
|
|
||||||
{
|
|
||||||
public string Slug { get; }
|
|
||||||
public string Name { get; }
|
|
||||||
public string Description { get; }
|
|
||||||
public string HelpMessage { get; }
|
|
||||||
public bool RunOnStartup { get; }
|
|
||||||
public int Priority { get; }
|
|
||||||
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null);
|
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters();
|
|
||||||
public int? Progress();
|
|
||||||
}
|
|
||||||
}
|
|
24
Kyoo.Common/Module.cs
Normal file
24
Kyoo.Common/Module.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using Kyoo.Controllers;
|
||||||
|
using Unity;
|
||||||
|
|
||||||
|
namespace Kyoo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A static class with helper functions to setup external modules
|
||||||
|
/// </summary>
|
||||||
|
public static class Module
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Register a new task to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The container</param>
|
||||||
|
/// <typeparam name="T">The type of the task</typeparam>
|
||||||
|
/// <returns>The initial container.</returns>
|
||||||
|
public static IUnityContainer AddTask<T>(this IUnityContainer services)
|
||||||
|
where T : class, ITask
|
||||||
|
{
|
||||||
|
services.RegisterSingleton<ITask, T>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -529,9 +529,9 @@ namespace Kyoo
|
|||||||
await action(i);
|
await action(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInfo GetMethod(Type type, BindingFlags flag, string name, Type[] generics, object[] args)
|
public static MethodInfo GetMethod(Type type, BindingFlags flag, string name, Type[] generics, object[] args)
|
||||||
{
|
{
|
||||||
MethodInfo[] methods = type.GetMethods(flag | BindingFlags.Public | BindingFlags.NonPublic)
|
MethodInfo[] methods = type.GetMethods(flag | BindingFlags.Public)
|
||||||
.Where(x => x.Name == name)
|
.Where(x => x.Name == name)
|
||||||
.Where(x => x.GetGenericArguments().Length == generics.Length)
|
.Where(x => x.GetGenericArguments().Length == generics.Length)
|
||||||
.Where(x => x.GetParameters().Length == args.Length)
|
.Where(x => x.GetParameters().Length == args.Length)
|
||||||
|
@ -1,56 +1,129 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models.Attributes;
|
||||||
using Kyoo.Tasks;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Unity;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A service to handle long running tasks and a background runner.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Task will be queued, only one can run simultaneously.</remarks>
|
||||||
public class TaskManager : BackgroundService, ITaskManager
|
public class TaskManager : BackgroundService, ITaskManager
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
/// <summary>
|
||||||
private readonly IPluginManager _pluginManager;
|
/// The service provider used to activate
|
||||||
|
/// </summary>
|
||||||
|
private readonly IUnityContainer _container;
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration instance used to get schedule informations
|
||||||
|
/// </summary>
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
|
/// <summary>
|
||||||
private List<(ITask task, DateTime scheduledDate)> _tasks = new List<(ITask, DateTime)>();
|
/// The logger instance.
|
||||||
private CancellationTokenSource _taskToken = new CancellationTokenSource();
|
/// </summary>
|
||||||
|
private readonly ILogger<TaskManager> _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of tasks and their next scheduled run.
|
||||||
|
/// </summary>
|
||||||
|
private List<(ITask task, DateTime scheduledDate)> _tasks;
|
||||||
|
/// <summary>
|
||||||
|
/// The queue of tasks that should be runned as soon as possible.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Queue<(ITask, Dictionary<string, object>)> _queuedTasks = new();
|
||||||
|
/// <summary>
|
||||||
|
/// The currently running task.
|
||||||
|
/// </summary>
|
||||||
private ITask _runningTask;
|
private ITask _runningTask;
|
||||||
private Queue<(ITask, string)> _queuedTasks = new Queue<(ITask, string)>();
|
/// <summary>
|
||||||
|
/// The cancellation token used to cancel the running task when the runner should shutdown.
|
||||||
|
/// </summary>
|
||||||
|
private readonly CancellationTokenSource _taskToken = new();
|
||||||
|
|
||||||
public TaskManager(IServiceProvider serviceProvider, IPluginManager pluginManager, IConfiguration configuration)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="TaskManager"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tasks">The list of tasks to manage</param>
|
||||||
|
/// <param name="container">The service provider to request services for tasks</param>
|
||||||
|
/// <param name="configuration">The configuration to load schedule information.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public TaskManager(IEnumerable<ITask> tasks,
|
||||||
|
IUnityContainer container,
|
||||||
|
IConfiguration configuration,
|
||||||
|
ILogger<TaskManager> logger)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_tasks = tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList();
|
||||||
_pluginManager = pluginManager;
|
_container = container;
|
||||||
_configuration = configuration;
|
_configuration = configuration.GetSection("scheduledTasks");
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when the application host is ready to start the service.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Start the runner in another thread.</remarks>
|
||||||
|
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
|
||||||
|
public override Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Task.Run(() => base.StartAsync(cancellationToken), CancellationToken.None);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_taskToken.Cancel();
|
||||||
|
return base.StopAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The runner that will host tasks and run queued tasks.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">A token to stop the runner</param>
|
||||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ReloadTask();
|
EnqueueStartupTasks();
|
||||||
|
|
||||||
IEnumerable<ITask> startupTasks = _tasks.Select(x => x.task)
|
|
||||||
.Where(x => x.RunOnStartup && x.Priority != Int32.MaxValue)
|
|
||||||
.OrderByDescending(x => x.Priority);
|
|
||||||
foreach (ITask task in startupTasks)
|
|
||||||
_queuedTasks.Enqueue((task, null));
|
|
||||||
|
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (_queuedTasks.Any())
|
if (_queuedTasks.Any())
|
||||||
{
|
{
|
||||||
(ITask task, string arguments) = _queuedTasks.Dequeue();
|
(ITask task, Dictionary<string, object> arguments) = _queuedTasks.Dequeue();
|
||||||
_runningTask = task;
|
_runningTask = task;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await task.Run(_serviceProvider, _taskToken.Token, arguments);
|
ICollection<TaskParameter> all = task.GetParameters();
|
||||||
|
TaskParameters args = new(arguments
|
||||||
|
.Select(x => (value: x, arg: all
|
||||||
|
.FirstOrDefault(y => string.Equals(y.Name, x.Key, StringComparison.OrdinalIgnoreCase))))
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
if (x.arg == null)
|
||||||
|
throw new ArgumentException($"Invalid argument name: {x.value.Key}");
|
||||||
|
return x.arg.CreateValue(x.value.Value);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogInformation("Task starting: {Task}", task.Name);
|
||||||
|
InjectServices(task);
|
||||||
|
await task.Run(args, _taskToken.Token);
|
||||||
|
_logger.LogInformation("Task finished: {Task}", task.Name);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"An unhandled exception occured while running the task {task.Name}.\nInner exception: {e.Message}\n\n");
|
_logger.LogError("An unhandled exception occured while running the task {Task}.\n" +
|
||||||
|
"Inner exception: {Exception}\n\n", task.Name, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -61,67 +134,90 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inject services into the <see cref="InjectedAttribute"/> marked properties of the given object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to inject</param>
|
||||||
|
/// <typeparam name="T">The type of the object.</typeparam>
|
||||||
|
private void InjectServices<T>(T obj)
|
||||||
|
{
|
||||||
|
IEnumerable<PropertyInfo> properties = typeof(T).GetProperties()
|
||||||
|
.Where(x => x.GetCustomAttribute<InjectedAttribute>() != null)
|
||||||
|
.Where(x => x.CanWrite);
|
||||||
|
|
||||||
|
foreach (PropertyInfo property in properties)
|
||||||
|
{
|
||||||
|
object value = _container.Resolve(property.PropertyType);
|
||||||
|
property.SetValue(obj, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start tasks that are scheduled for start.
|
||||||
|
/// </summary>
|
||||||
private void QueueScheduledTasks()
|
private void QueueScheduledTasks()
|
||||||
{
|
{
|
||||||
IEnumerable<string> tasksToQueue = _tasks.Where(x => x.scheduledDate <= DateTime.Now)
|
IEnumerable<string> tasksToQueue = _tasks.Where(x => x.scheduledDate <= DateTime.Now)
|
||||||
.Select(x => x.task.Slug);
|
.Select(x => x.task.Slug);
|
||||||
foreach (string task in tasksToQueue)
|
foreach (string task in tasksToQueue)
|
||||||
StartTask(task);
|
{
|
||||||
|
_logger.LogDebug("Queuing task scheduled for running: {Task}", task);
|
||||||
|
StartTask(task, new Dictionary<string, object>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task StartAsync(CancellationToken cancellationToken)
|
/// <summary>
|
||||||
|
/// Queue startup tasks with respect to the priority rules.
|
||||||
|
/// </summary>
|
||||||
|
private void EnqueueStartupTasks()
|
||||||
{
|
{
|
||||||
Task.Run(() => base.StartAsync(cancellationToken));
|
IEnumerable<ITask> startupTasks = _tasks.Select(x => x.task)
|
||||||
return Task.CompletedTask;
|
.Where(x => x.RunOnStartup && x.Priority != int.MaxValue)
|
||||||
|
.OrderByDescending(x => x.Priority);
|
||||||
|
foreach (ITask task in startupTasks)
|
||||||
|
_queuedTasks.Enqueue((task, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task StopAsync(CancellationToken cancellationToken)
|
/// <inheritdoc />
|
||||||
{
|
public void StartTask(string taskSlug, Dictionary<string, object> arguments)
|
||||||
_taskToken.Cancel();
|
|
||||||
return base.StopAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool StartTask(string taskSlug, string arguments = null)
|
|
||||||
{
|
{
|
||||||
int index = _tasks.FindIndex(x => x.task.Slug == taskSlug);
|
int index = _tasks.FindIndex(x => x.task.Slug == taskSlug);
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
return false;
|
throw new ItemNotFound($"No task found with the slug {taskSlug}");
|
||||||
_queuedTasks.Enqueue((_tasks[index].task, arguments));
|
_queuedTasks.Enqueue((_tasks[index].task, arguments));
|
||||||
_tasks[index] = (_tasks[index].task, DateTime.Now + GetTaskDelay(taskSlug));
|
_tasks[index] = (_tasks[index].task, DateTime.Now + GetTaskDelay(taskSlug));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan GetTaskDelay(string taskSlug)
|
/// <summary>
|
||||||
|
/// Get the delay of a task
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskSlug">The slug of the task</param>
|
||||||
|
/// <returns>The delay of the task.</returns>
|
||||||
|
private TimeSpan GetTaskDelay(string taskSlug)
|
||||||
{
|
{
|
||||||
TimeSpan delay = _configuration.GetSection("scheduledTasks").GetValue<TimeSpan>(taskSlug);
|
TimeSpan delay = _configuration.GetValue<TimeSpan>(taskSlug);
|
||||||
if (delay == default)
|
if (delay == default)
|
||||||
delay = TimeSpan.FromDays(365);
|
delay = TimeSpan.MaxValue;
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITask GetRunningTask()
|
/// <inheritdoc />
|
||||||
|
public ICollection<ITask> GetRunningTasks()
|
||||||
{
|
{
|
||||||
return _runningTask;
|
return new[] {_runningTask};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadTask()
|
/// <inheritdoc />
|
||||||
|
public ICollection<ITask> GetAllTasks()
|
||||||
{
|
{
|
||||||
_tasks.Clear();
|
return _tasks.Select(x => x.task).ToArray();
|
||||||
_tasks.AddRange(CoreTaskHolder.Tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))));
|
|
||||||
|
|
||||||
IEnumerable<ITask> prerunTasks = _tasks.Select(x => x.task)
|
|
||||||
.Where(x => x.RunOnStartup && x.Priority == int.MaxValue);
|
|
||||||
|
|
||||||
foreach (ITask task in prerunTasks)
|
|
||||||
task.Run(_serviceProvider, _taskToken.Token);
|
|
||||||
foreach (IPlugin plugin in _pluginManager.GetAllPlugins())
|
|
||||||
if (plugin.Tasks != null)
|
|
||||||
_tasks.AddRange(plugin.Tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ITask> GetAllTasks()
|
/// <inheritdoc />
|
||||||
|
public void ReloadTasks()
|
||||||
{
|
{
|
||||||
return _tasks.Select(x => x.task);
|
_tasks = _container.ResolveAll<ITask>().Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList();
|
||||||
|
EnqueueStartupTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
26
Kyoo/CoreModule.cs
Normal file
26
Kyoo/CoreModule.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Kyoo.Controllers;
|
||||||
|
using Unity;
|
||||||
|
|
||||||
|
namespace Kyoo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The core module ccontaining default implementations
|
||||||
|
/// </summary>
|
||||||
|
public class CoreModule : IPlugin
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Slug => "core";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "Core";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "The core module containing default implementations.";
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IPlugin.Configure" />
|
||||||
|
public static void Configure(IUnityContainer container)
|
||||||
|
{
|
||||||
|
container.AddTask<Crawler>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Unity.Container" Version="5.11.11" />
|
||||||
|
<PackageReference Include="Unity.Microsoft.DependencyInjection" Version="5.11.5" />
|
||||||
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
|
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
|
||||||
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
|
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
|
||||||
<PackageReference Include="IdentityServer4" Version="4.1.1" />
|
<PackageReference Include="IdentityServer4" Version="4.1.1" />
|
||||||
@ -56,7 +58,6 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="5.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Unity;
|
||||||
|
using Unity.Microsoft.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
@ -39,6 +40,7 @@ namespace Kyoo
|
|||||||
|
|
||||||
if (debug == null && Environment.GetEnvironmentVariable("ENVIRONMENT") != null)
|
if (debug == null && Environment.GetEnvironmentVariable("ENVIRONMENT") != null)
|
||||||
Console.WriteLine($"Invalid ENVIRONMENT variable. Supported values are \"debug\" and \"prod\". Ignoring...");
|
Console.WriteLine($"Invalid ENVIRONMENT variable. Supported values are \"debug\" and \"prod\". Ignoring...");
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
debug ??= true;
|
debug ??= true;
|
||||||
#endif
|
#endif
|
||||||
@ -70,7 +72,8 @@ namespace Kyoo
|
|||||||
/// <returns>A new web host instance</returns>
|
/// <returns>A new web host instance</returns>
|
||||||
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
||||||
{
|
{
|
||||||
WebHost.CreateDefaultBuilder(args);
|
UnityContainer container = new();
|
||||||
|
container.EnableDebugDiagnostic();
|
||||||
|
|
||||||
return new WebHostBuilder()
|
return new WebHostBuilder()
|
||||||
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
||||||
@ -89,6 +92,7 @@ namespace Kyoo
|
|||||||
if (context.HostingEnvironment.IsDevelopment())
|
if (context.HostingEnvironment.IsDevelopment())
|
||||||
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
|
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
|
||||||
})
|
})
|
||||||
|
.UseUnityServiceProvider(container)
|
||||||
.ConfigureServices(x => x.AddRouting())
|
.ConfigureServices(x => x.AddRouting())
|
||||||
.UseKestrel(options => { options.AddServerHeader = false; })
|
.UseKestrel(options => { options.AddServerHeader = false; })
|
||||||
.UseIIS()
|
.UseIIS()
|
||||||
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Unity;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
@ -185,7 +186,7 @@ namespace Kyoo
|
|||||||
services.AddHostedService(provider => (TaskManager)provider.GetService<ITaskManager>());
|
services.AddHostedService(provider => (TaskManager)provider.GetService<ITaskManager>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IUnityContainer container)
|
||||||
{
|
{
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
@ -247,6 +248,9 @@ namespace Kyoo
|
|||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
spa.UseAngularCliServer("start");
|
spa.UseAngularCliServer("start");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CoreModule.Configure(container);
|
||||||
|
container.Resolve<ITaskManager>().ReloadTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
|
|
||||||
namespace Kyoo.Tasks
|
|
||||||
{
|
|
||||||
public static class CoreTaskHolder
|
|
||||||
{
|
|
||||||
public static readonly ITask[] Tasks =
|
|
||||||
{
|
|
||||||
new CreateDatabase(),
|
|
||||||
new PluginLoader(),
|
|
||||||
new Crawler(),
|
|
||||||
new MetadataProviderLoader(),
|
|
||||||
// new ReScan(),
|
|
||||||
new ExtractMetadata()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Models.Attributes;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@ -21,19 +22,20 @@ namespace Kyoo.Controllers
|
|||||||
public bool RunOnStartup => true;
|
public bool RunOnStartup => true;
|
||||||
public int Priority => 0;
|
public int Priority => 0;
|
||||||
|
|
||||||
private IServiceProvider _serviceProvider;
|
[Injected] public IServiceProvider ServiceProvider { private get; set; }
|
||||||
private IThumbnailsManager _thumbnailsManager;
|
[Injected] public IThumbnailsManager ThumbnailsManager { private get; set; }
|
||||||
private IProviderManager _metadataProvider;
|
[Injected] public IProviderManager MetadataProvider { private get; set; }
|
||||||
private ITranscoder _transcoder;
|
[Injected] public ITranscoder Transcoder { private get; set; }
|
||||||
private IConfiguration _config;
|
[Injected] public IConfiguration Config { private get; set; }
|
||||||
|
|
||||||
private int _parallelTasks;
|
private int _parallelTasks;
|
||||||
|
|
||||||
public async Task<IEnumerable<string>> GetPossibleParameters()
|
public TaskParameters GetParameters()
|
||||||
{
|
{
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
return new()
|
||||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
{
|
||||||
return (await libraryManager!.GetAll<Library>()).Select(x => x.Slug);
|
TaskParameter.Create<string>("slug", "A library slug to restrict the scan to this library.")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? Progress()
|
public int? Progress()
|
||||||
@ -42,20 +44,16 @@ namespace Kyoo.Controllers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run(IServiceProvider serviceProvider,
|
public async Task Run(TaskParameters parameters,
|
||||||
CancellationToken cancellationToken,
|
CancellationToken cancellationToken)
|
||||||
string argument = null)
|
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
string argument = parameters["slug"].As<string>();
|
||||||
_thumbnailsManager = serviceProvider.GetService<IThumbnailsManager>();
|
|
||||||
_metadataProvider = serviceProvider.GetService<IProviderManager>();
|
_parallelTasks = Config.GetValue<int>("parallelTasks");
|
||||||
_transcoder = serviceProvider.GetService<ITranscoder>();
|
|
||||||
_config = serviceProvider.GetService<IConfiguration>();
|
|
||||||
_parallelTasks = _config.GetValue<int>("parallelTasks");
|
|
||||||
if (_parallelTasks <= 0)
|
if (_parallelTasks <= 0)
|
||||||
_parallelTasks = 30;
|
_parallelTasks = 30;
|
||||||
|
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
using IServiceScope serviceScope = ServiceProvider.CreateScope();
|
||||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||||
|
|
||||||
foreach (Show show in await libraryManager!.GetAll<Show>())
|
foreach (Show show in await libraryManager!.GetAll<Show>())
|
||||||
@ -148,10 +146,10 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
if (token.IsCancellationRequested || path.Split(Path.DirectorySeparatorChar).Contains("Subtitles"))
|
if (token.IsCancellationRequested || path.Split(Path.DirectorySeparatorChar).Contains("Subtitles"))
|
||||||
return;
|
return;
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
using IServiceScope serviceScope = ServiceProvider.CreateScope();
|
||||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||||
|
|
||||||
string patern = _config.GetValue<string>("subtitleRegex");
|
string patern = Config.GetValue<string>("subtitleRegex");
|
||||||
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
||||||
Match match = regex.Match(path);
|
Match match = regex.Match(path);
|
||||||
|
|
||||||
@ -195,10 +193,10 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
using IServiceScope serviceScope = ServiceProvider.CreateScope();
|
||||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||||
|
|
||||||
string patern = _config.GetValue<string>("regex");
|
string patern = Config.GetValue<string>("regex");
|
||||||
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
||||||
Match match = regex.Match(relativePath);
|
Match match = regex.Match(relativePath);
|
||||||
|
|
||||||
@ -257,7 +255,7 @@ namespace Kyoo.Controllers
|
|||||||
Collection collection = await libraryManager.Get<Collection>(Utility.ToSlug(collectionName));
|
Collection collection = await libraryManager.Get<Collection>(Utility.ToSlug(collectionName));
|
||||||
if (collection != null)
|
if (collection != null)
|
||||||
return collection;
|
return collection;
|
||||||
collection = await _metadataProvider.GetCollectionFromName(collectionName, library);
|
collection = await MetadataProvider.GetCollectionFromName(collectionName, library);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -282,9 +280,9 @@ namespace Kyoo.Controllers
|
|||||||
await libraryManager.Load(old, x => x.ExternalIDs);
|
await libraryManager.Load(old, x => x.ExternalIDs);
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
Show show = await _metadataProvider.SearchShow(showTitle, isMovie, library);
|
Show show = await MetadataProvider.SearchShow(showTitle, isMovie, library);
|
||||||
show.Path = showPath;
|
show.Path = showPath;
|
||||||
show.People = await _metadataProvider.GetPeople(show, library);
|
show.People = await MetadataProvider.GetPeople(show, library);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -301,7 +299,7 @@ namespace Kyoo.Controllers
|
|||||||
show.Slug += $"-{show.StartYear}";
|
show.Slug += $"-{show.StartYear}";
|
||||||
await libraryManager.Create(show);
|
await libraryManager.Create(show);
|
||||||
}
|
}
|
||||||
await _thumbnailsManager.Validate(show);
|
await ThumbnailsManager.Validate(show);
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,9 +318,9 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
catch (ItemNotFound)
|
catch (ItemNotFound)
|
||||||
{
|
{
|
||||||
Season season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
Season season = await MetadataProvider.GetSeason(show, seasonNumber, library);
|
||||||
await libraryManager.CreateIfNotExists(season);
|
await libraryManager.CreateIfNotExists(season);
|
||||||
await _thumbnailsManager.Validate(season);
|
await ThumbnailsManager.Validate(season);
|
||||||
season.Show = show;
|
season.Show = show;
|
||||||
return season;
|
return season;
|
||||||
}
|
}
|
||||||
@ -336,7 +334,7 @@ namespace Kyoo.Controllers
|
|||||||
string episodePath,
|
string episodePath,
|
||||||
Library library)
|
Library library)
|
||||||
{
|
{
|
||||||
Episode episode = await _metadataProvider.GetEpisode(show,
|
Episode episode = await MetadataProvider.GetEpisode(show,
|
||||||
episodePath,
|
episodePath,
|
||||||
season?.SeasonNumber ?? -1,
|
season?.SeasonNumber ?? -1,
|
||||||
episodeNumber,
|
episodeNumber,
|
||||||
@ -346,7 +344,7 @@ namespace Kyoo.Controllers
|
|||||||
season ??= await GetSeason(libraryManager, show, episode.SeasonNumber, library);
|
season ??= await GetSeason(libraryManager, show, episode.SeasonNumber, library);
|
||||||
episode.Season = season;
|
episode.Season = season;
|
||||||
episode.SeasonID = season?.ID;
|
episode.SeasonID = season?.ID;
|
||||||
await _thumbnailsManager.Validate(episode);
|
await ThumbnailsManager.Validate(episode);
|
||||||
await GetTracks(episode);
|
await GetTracks(episode);
|
||||||
return episode;
|
return episode;
|
||||||
}
|
}
|
||||||
@ -367,7 +365,7 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
private async Task<ICollection<Track>> GetTracks(Episode episode)
|
private async Task<ICollection<Track>> GetTracks(Episode episode)
|
||||||
{
|
{
|
||||||
episode.Tracks = (await _transcoder.ExtractInfos(episode, false))
|
episode.Tracks = (await Transcoder.ExtractInfos(episode, false))
|
||||||
.Where(x => x.Type != StreamType.Attachment)
|
.Where(x => x.Type != StreamType.Attachment)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
return episode.Tracks;
|
return episode.Tracks;
|
||||||
|
@ -1,66 +1,66 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Linq;
|
// using System.Linq;
|
||||||
using System.Threading;
|
// using System.Threading;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
using IdentityServer4.EntityFramework.DbContexts;
|
// using IdentityServer4.EntityFramework.DbContexts;
|
||||||
using IdentityServer4.EntityFramework.Mappers;
|
// using IdentityServer4.EntityFramework.Mappers;
|
||||||
using IdentityServer4.Models;
|
// using IdentityServer4.Models;
|
||||||
using Kyoo.Models;
|
// using Kyoo.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
// using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
// using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//
|
||||||
namespace Kyoo.Tasks
|
// namespace Kyoo.Tasks
|
||||||
{
|
// {
|
||||||
public class CreateDatabase : ITask
|
// public class CreateDatabase : ITask
|
||||||
{
|
// {
|
||||||
public string Slug => "create-database";
|
// public string Slug => "create-database";
|
||||||
public string Name => "Create the database";
|
// public string Name => "Create the database";
|
||||||
public string Description => "Create the database if it does not exit and initialize it with defaults value.";
|
// public string Description => "Create the database if it does not exit and initialize it with defaults value.";
|
||||||
public string HelpMessage => null;
|
// public string HelpMessage => null;
|
||||||
public bool RunOnStartup => true;
|
// public bool RunOnStartup => true;
|
||||||
public int Priority => int.MaxValue;
|
// public int Priority => int.MaxValue;
|
||||||
|
//
|
||||||
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
// public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
||||||
{
|
// {
|
||||||
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
// using IServiceScope serviceScope = serviceProvider.CreateScope();
|
||||||
DatabaseContext databaseContext = serviceScope.ServiceProvider.GetService<DatabaseContext>();
|
// DatabaseContext databaseContext = serviceScope.ServiceProvider.GetService<DatabaseContext>();
|
||||||
IdentityDatabase identityDatabase = serviceScope.ServiceProvider.GetService<IdentityDatabase>();
|
// IdentityDatabase identityDatabase = serviceScope.ServiceProvider.GetService<IdentityDatabase>();
|
||||||
ConfigurationDbContext identityContext = serviceScope.ServiceProvider.GetService<ConfigurationDbContext>();
|
// ConfigurationDbContext identityContext = serviceScope.ServiceProvider.GetService<ConfigurationDbContext>();
|
||||||
|
//
|
||||||
databaseContext!.Database.Migrate();
|
// databaseContext!.Database.Migrate();
|
||||||
identityDatabase!.Database.Migrate();
|
// identityDatabase!.Database.Migrate();
|
||||||
identityContext!.Database.Migrate();
|
// identityContext!.Database.Migrate();
|
||||||
|
//
|
||||||
if (!identityContext.Clients.Any())
|
// if (!identityContext.Clients.Any())
|
||||||
{
|
// {
|
||||||
foreach (Client client in IdentityContext.GetClients())
|
// foreach (Client client in IdentityContext.GetClients())
|
||||||
identityContext.Clients.Add(client.ToEntity());
|
// identityContext.Clients.Add(client.ToEntity());
|
||||||
identityContext.SaveChanges();
|
// identityContext.SaveChanges();
|
||||||
}
|
// }
|
||||||
if (!identityContext.IdentityResources.Any())
|
// if (!identityContext.IdentityResources.Any())
|
||||||
{
|
// {
|
||||||
foreach (IdentityResource resource in IdentityContext.GetIdentityResources())
|
// foreach (IdentityResource resource in IdentityContext.GetIdentityResources())
|
||||||
identityContext.IdentityResources.Add(resource.ToEntity());
|
// identityContext.IdentityResources.Add(resource.ToEntity());
|
||||||
identityContext.SaveChanges();
|
// identityContext.SaveChanges();
|
||||||
}
|
// }
|
||||||
if (!identityContext.ApiResources.Any())
|
// if (!identityContext.ApiResources.Any())
|
||||||
{
|
// {
|
||||||
foreach (ApiResource resource in IdentityContext.GetApis())
|
// foreach (ApiResource resource in IdentityContext.GetApis())
|
||||||
identityContext.ApiResources.Add(resource.ToEntity());
|
// identityContext.ApiResources.Add(resource.ToEntity());
|
||||||
identityContext.SaveChanges();
|
// identityContext.SaveChanges();
|
||||||
}
|
// }
|
||||||
return Task.CompletedTask;
|
// return Task.CompletedTask;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
// public Task<IEnumerable<string>> GetPossibleParameters()
|
||||||
{
|
// {
|
||||||
return Task.FromResult<IEnumerable<string>>(null);
|
// return Task.FromResult<IEnumerable<string>>(null);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public int? Progress()
|
// public int? Progress()
|
||||||
{
|
// {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -1,120 +1,120 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Linq;
|
// using System.Linq;
|
||||||
using System.Threading;
|
// using System.Threading;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
using Kyoo.Controllers;
|
// using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
// using Kyoo.Models;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
// using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//
|
||||||
namespace Kyoo.Tasks
|
// namespace Kyoo.Tasks
|
||||||
{
|
// {
|
||||||
public class ExtractMetadata : ITask
|
// public class ExtractMetadata : ITask
|
||||||
{
|
// {
|
||||||
public string Slug => "extract";
|
// public string Slug => "extract";
|
||||||
public string Name => "Metadata Extractor";
|
// public string Name => "Metadata Extractor";
|
||||||
public string Description => "Extract subtitles or download thumbnails for a show/episode.";
|
// public string Description => "Extract subtitles or download thumbnails for a show/episode.";
|
||||||
public string HelpMessage => null;
|
// public string HelpMessage => null;
|
||||||
public bool RunOnStartup => false;
|
// public bool RunOnStartup => false;
|
||||||
public int Priority => 0;
|
// public int Priority => 0;
|
||||||
|
//
|
||||||
|
//
|
||||||
private ILibraryManager _library;
|
// private ILibraryManager _library;
|
||||||
private IThumbnailsManager _thumbnails;
|
// private IThumbnailsManager _thumbnails;
|
||||||
private ITranscoder _transcoder;
|
// private ITranscoder _transcoder;
|
||||||
|
//
|
||||||
public async Task Run(IServiceProvider serviceProvider, CancellationToken token, string arguments = null)
|
// public async Task Run(IServiceProvider serviceProvider, CancellationToken token, string arguments = null)
|
||||||
{
|
// {
|
||||||
string[] args = arguments?.Split('/');
|
// string[] args = arguments?.Split('/');
|
||||||
|
//
|
||||||
if (args == null || args.Length < 2)
|
// if (args == null || args.Length < 2)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
string slug = args[1];
|
// string slug = args[1];
|
||||||
bool thumbs = args.Length < 3 || string.Equals(args[2], "thumbnails", StringComparison.InvariantCultureIgnoreCase);
|
// bool thumbs = args.Length < 3 || string.Equals(args[2], "thumbnails", StringComparison.InvariantCultureIgnoreCase);
|
||||||
bool subs = args.Length < 3 || string.Equals(args[2], "subs", StringComparison.InvariantCultureIgnoreCase);
|
// bool subs = args.Length < 3 || string.Equals(args[2], "subs", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
//
|
||||||
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
// using IServiceScope serviceScope = serviceProvider.CreateScope();
|
||||||
_library = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
// _library = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||||
_thumbnails = serviceScope.ServiceProvider.GetService<IThumbnailsManager>();
|
// _thumbnails = serviceScope.ServiceProvider.GetService<IThumbnailsManager>();
|
||||||
_transcoder = serviceScope.ServiceProvider.GetService<ITranscoder>();
|
// _transcoder = serviceScope.ServiceProvider.GetService<ITranscoder>();
|
||||||
int id;
|
// int id;
|
||||||
|
//
|
||||||
switch (args[0].ToLowerInvariant())
|
// switch (args[0].ToLowerInvariant())
|
||||||
{
|
// {
|
||||||
case "show":
|
// case "show":
|
||||||
case "shows":
|
// case "shows":
|
||||||
Show show = await (int.TryParse(slug, out id)
|
// Show show = await (int.TryParse(slug, out id)
|
||||||
? _library!.Get<Show>(id)
|
// ? _library!.Get<Show>(id)
|
||||||
: _library!.Get<Show>(slug));
|
// : _library!.Get<Show>(slug));
|
||||||
await ExtractShow(show, thumbs, subs, token);
|
// await ExtractShow(show, thumbs, subs, token);
|
||||||
break;
|
// break;
|
||||||
case "season":
|
// case "season":
|
||||||
case "seasons":
|
// case "seasons":
|
||||||
Season season = await (int.TryParse(slug, out id)
|
// Season season = await (int.TryParse(slug, out id)
|
||||||
? _library!.Get<Season>(id)
|
// ? _library!.Get<Season>(id)
|
||||||
: _library!.Get<Season>(slug));
|
// : _library!.Get<Season>(slug));
|
||||||
await ExtractSeason(season, thumbs, subs, token);
|
// await ExtractSeason(season, thumbs, subs, token);
|
||||||
break;
|
// break;
|
||||||
case "episode":
|
// case "episode":
|
||||||
case "episodes":
|
// case "episodes":
|
||||||
Episode episode = await (int.TryParse(slug, out id)
|
// Episode episode = await (int.TryParse(slug, out id)
|
||||||
? _library!.Get<Episode>(id)
|
// ? _library!.Get<Episode>(id)
|
||||||
: _library!.Get<Episode>(slug));
|
// : _library!.Get<Episode>(slug));
|
||||||
await ExtractEpisode(episode, thumbs, subs);
|
// await ExtractEpisode(episode, thumbs, subs);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private async Task ExtractShow(Show show, bool thumbs, bool subs, CancellationToken token)
|
// private async Task ExtractShow(Show show, bool thumbs, bool subs, CancellationToken token)
|
||||||
{
|
// {
|
||||||
if (thumbs)
|
// if (thumbs)
|
||||||
await _thumbnails!.Validate(show, true);
|
// await _thumbnails!.Validate(show, true);
|
||||||
await _library.Load(show, x => x.Seasons);
|
// await _library.Load(show, x => x.Seasons);
|
||||||
foreach (Season season in show.Seasons)
|
// foreach (Season season in show.Seasons)
|
||||||
{
|
// {
|
||||||
if (token.IsCancellationRequested)
|
// if (token.IsCancellationRequested)
|
||||||
return;
|
// return;
|
||||||
await ExtractSeason(season, thumbs, subs, token);
|
// await ExtractSeason(season, thumbs, subs, token);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private async Task ExtractSeason(Season season, bool thumbs, bool subs, CancellationToken token)
|
// private async Task ExtractSeason(Season season, bool thumbs, bool subs, CancellationToken token)
|
||||||
{
|
// {
|
||||||
if (thumbs)
|
// if (thumbs)
|
||||||
await _thumbnails!.Validate(season, true);
|
// await _thumbnails!.Validate(season, true);
|
||||||
await _library.Load(season, x => x.Episodes);
|
// await _library.Load(season, x => x.Episodes);
|
||||||
foreach (Episode episode in season.Episodes)
|
// foreach (Episode episode in season.Episodes)
|
||||||
{
|
// {
|
||||||
if (token.IsCancellationRequested)
|
// if (token.IsCancellationRequested)
|
||||||
return;
|
// return;
|
||||||
await ExtractEpisode(episode, thumbs, subs);
|
// await ExtractEpisode(episode, thumbs, subs);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private async Task ExtractEpisode(Episode episode, bool thumbs, bool subs)
|
// private async Task ExtractEpisode(Episode episode, bool thumbs, bool subs)
|
||||||
{
|
// {
|
||||||
if (thumbs)
|
// if (thumbs)
|
||||||
await _thumbnails!.Validate(episode, true);
|
// await _thumbnails!.Validate(episode, true);
|
||||||
if (subs)
|
// if (subs)
|
||||||
{
|
// {
|
||||||
await _library.Load(episode, x => x.Tracks);
|
// await _library.Load(episode, x => x.Tracks);
|
||||||
episode.Tracks = (await _transcoder!.ExtractInfos(episode, true))
|
// episode.Tracks = (await _transcoder!.ExtractInfos(episode, true))
|
||||||
.Where(x => x.Type != StreamType.Attachment)
|
// .Where(x => x.Type != StreamType.Attachment)
|
||||||
.Concat(episode.Tracks.Where(x => x.IsExternal))
|
// .Concat(episode.Tracks.Where(x => x.IsExternal))
|
||||||
.ToList();
|
// .ToList();
|
||||||
await _library.Edit(episode, false);
|
// await _library.Edit(episode, false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
// public Task<IEnumerable<string>> GetPossibleParameters()
|
||||||
{
|
// {
|
||||||
return Task.FromResult<IEnumerable<string>>(null);
|
// return Task.FromResult<IEnumerable<string>>(null);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public int? Progress()
|
// public int? Progress()
|
||||||
{
|
// {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -1,46 +1,46 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Threading;
|
// using System.Threading;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
using Kyoo.Controllers;
|
// using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
// using Kyoo.Models;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
// using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//
|
||||||
namespace Kyoo.Tasks
|
// namespace Kyoo.Tasks
|
||||||
{
|
// {
|
||||||
public class MetadataProviderLoader : ITask
|
// public class MetadataProviderLoader : ITask
|
||||||
{
|
// {
|
||||||
public string Slug => "reload-metdata";
|
// public string Slug => "reload-metdata";
|
||||||
public string Name => "Reload Metadata Providers";
|
// public string Name => "Reload Metadata Providers";
|
||||||
public string Description => "Add every loaded metadata provider to the database.";
|
// public string Description => "Add every loaded metadata provider to the database.";
|
||||||
public string HelpMessage => null;
|
// public string HelpMessage => null;
|
||||||
public bool RunOnStartup => true;
|
// public bool RunOnStartup => true;
|
||||||
public int Priority => 1000;
|
// public int Priority => 1000;
|
||||||
|
//
|
||||||
public async Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
// public async Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
||||||
{
|
// {
|
||||||
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
// using IServiceScope serviceScope = serviceProvider.CreateScope();
|
||||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
// IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||||
IThumbnailsManager thumbnails = serviceScope.ServiceProvider.GetService<IThumbnailsManager>();
|
// IThumbnailsManager thumbnails = serviceScope.ServiceProvider.GetService<IThumbnailsManager>();
|
||||||
IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
// IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
||||||
|
//
|
||||||
foreach (IMetadataProvider provider in pluginManager!.GetPlugins<IMetadataProvider>())
|
// foreach (IMetadataProvider provider in pluginManager!.GetPlugins<IMetadataProvider>())
|
||||||
{
|
// {
|
||||||
if (string.IsNullOrEmpty(provider.Provider.Slug))
|
// if (string.IsNullOrEmpty(provider.Provider.Slug))
|
||||||
throw new ArgumentException($"Empty provider slug (name: {provider.Provider.Name}).");
|
// throw new ArgumentException($"Empty provider slug (name: {provider.Provider.Name}).");
|
||||||
await providers!.CreateIfNotExists(provider.Provider);
|
// await providers!.CreateIfNotExists(provider.Provider);
|
||||||
await thumbnails!.Validate(provider.Provider);
|
// await thumbnails!.Validate(provider.Provider);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
// public Task<IEnumerable<string>> GetPossibleParameters()
|
||||||
{
|
// {
|
||||||
return Task.FromResult<IEnumerable<string>>(null);
|
// return Task.FromResult<IEnumerable<string>>(null);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public int? Progress()
|
// public int? Progress()
|
||||||
{
|
// {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -1,37 +1,37 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Threading;
|
// using System.Threading;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
using Kyoo.Controllers;
|
// using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
// using Kyoo.Models;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
// using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//
|
||||||
namespace Kyoo.Tasks
|
// namespace Kyoo.Tasks
|
||||||
{
|
// {
|
||||||
public class PluginLoader : ITask
|
// public class PluginLoader : ITask
|
||||||
{
|
// {
|
||||||
public string Slug => "reload-plugin";
|
// public string Slug => "reload-plugin";
|
||||||
public string Name => "Reload plugins";
|
// public string Name => "Reload plugins";
|
||||||
public string Description => "Reload all plugins from the plugin folder.";
|
// public string Description => "Reload all plugins from the plugin folder.";
|
||||||
public string HelpMessage => null;
|
// public string HelpMessage => null;
|
||||||
public bool RunOnStartup => true;
|
// public bool RunOnStartup => true;
|
||||||
public int Priority => Int32.MaxValue;
|
// public int Priority => Int32.MaxValue;
|
||||||
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
// public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
||||||
{
|
// {
|
||||||
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
// using IServiceScope serviceScope = serviceProvider.CreateScope();
|
||||||
IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
// IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
||||||
pluginManager.ReloadPlugins();
|
// pluginManager.ReloadPlugins();
|
||||||
return Task.CompletedTask;
|
// return Task.CompletedTask;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
// public Task<IEnumerable<string>> GetPossibleParameters()
|
||||||
{
|
// {
|
||||||
return Task.FromResult<IEnumerable<string>>(null);
|
// return Task.FromResult<IEnumerable<string>>(null);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public int? Progress()
|
// public int? Progress()
|
||||||
{
|
// {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -32,7 +32,7 @@ namespace Kyoo.Api
|
|||||||
{
|
{
|
||||||
ActionResult<Library> result = await base.Create(resource);
|
ActionResult<Library> result = await base.Create(resource);
|
||||||
if (result.Value != null)
|
if (result.Value != null)
|
||||||
_taskManager.StartTask("scan", result.Value.Slug);
|
_taskManager.StartTask("scan", new Dictionary<string, object> {{"slug", result.Value.Slug}});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class TaskController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ITaskManager _taskManager;
|
|
||||||
|
|
||||||
public TaskController(ITaskManager taskManager)
|
|
||||||
{
|
|
||||||
_taskManager = taskManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet("{taskSlug}/{*args}")]
|
|
||||||
[HttpPut("{taskSlug}/{*args}")]
|
|
||||||
[Authorize(Policy="Admin")]
|
|
||||||
public IActionResult RunTask(string taskSlug, string args = null)
|
|
||||||
{
|
|
||||||
if (_taskManager.StartTask(taskSlug, args))
|
|
||||||
return Ok();
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
49
Kyoo/Views/TaskApi.cs
Normal file
49
Kyoo/Views/TaskApi.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/task")]
|
||||||
|
[Route("api/tasks")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize(Policy="Admin")]
|
||||||
|
public class TaskApi : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ITaskManager _taskManager;
|
||||||
|
|
||||||
|
public TaskApi(ITaskManager taskManager)
|
||||||
|
{
|
||||||
|
_taskManager = taskManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public ActionResult<ICollection<ITask>> GetTasks()
|
||||||
|
{
|
||||||
|
return Ok(_taskManager.GetAllTasks());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{taskSlug}")]
|
||||||
|
[HttpPut("{taskSlug}")]
|
||||||
|
public IActionResult RunTask(string taskSlug, [FromQuery] Dictionary<string, object> args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_taskManager.StartTask(taskSlug, args);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,10 +17,12 @@
|
|||||||
"logLevel": {
|
"logLevel": {
|
||||||
"default": "Warning",
|
"default": "Warning",
|
||||||
"Microsoft": "Warning",
|
"Microsoft": "Warning",
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
"Microsoft.Hosting.Lifetime": "Information",
|
||||||
|
"Kyoo": "Trace"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"parallelTasks": "1",
|
"parallelTasks": "1",
|
||||||
|
|
||||||
"scheduledTasks": {
|
"scheduledTasks": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user