浏览代码

move scheduled tasks to Jellyfin.Api

crobibero 5 年之前
父节点
当前提交
5d9c40ec72

+ 207 - 0
Jellyfin.Api/Controllers/ScheduledTasksController.cs

@@ -0,0 +1,207 @@
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Model.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+
+namespace Jellyfin.Api.Controllers
+{
+    /// <summary>
+    /// Scheduled Tasks Controller.
+    /// </summary>
+    public class ScheduledTasksController : BaseJellyfinApiController
+    {
+        private readonly ITaskManager _taskManager;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScheduledTasksController"/> class.
+        /// </summary>
+        /// <param name="taskManager">Instance of the <see cref="ITaskManager"/> interface.</param>
+        public ScheduledTasksController(ITaskManager taskManager)
+        {
+            _taskManager = taskManager;
+        }
+
+        /// <summary>
+        /// Get tasks.
+        /// </summary>
+        /// <param name="isHidden">Optional filter tasks that are hidden, or not.</param>
+        /// <param name="isEnabled">Optional filter tasks that are enabled, or not.</param>
+        /// <returns>Task list.</returns>
+        [HttpGet]
+        [ProducesResponseType(typeof(TaskInfo[]), StatusCodes.Status200OK)]
+        [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
+        public IActionResult GetTasks(
+            [FromQuery] bool? isHidden = false,
+            [FromQuery] bool? isEnabled = false)
+        {
+            try
+            {
+                IEnumerable<IScheduledTaskWorker> tasks = _taskManager.ScheduledTasks.OrderBy(o => o.Name);
+
+                if (isHidden.HasValue)
+                {
+                    var hiddenValue = isHidden.Value;
+                    tasks = tasks.Where(o =>
+                    {
+                        var itemIsHidden = false;
+                        if (o.ScheduledTask is IConfigurableScheduledTask configurableScheduledTask)
+                        {
+                            itemIsHidden = configurableScheduledTask.IsHidden;
+                        }
+
+                        return itemIsHidden == hiddenValue;
+                    });
+                }
+
+                if (isEnabled.HasValue)
+                {
+                    var enabledValue = isEnabled.Value;
+                    tasks = tasks.Where(o =>
+                    {
+                        var itemIsEnabled = false;
+                        if (o.ScheduledTask is IConfigurableScheduledTask configurableScheduledTask)
+                        {
+                            itemIsEnabled = configurableScheduledTask.IsEnabled;
+                        }
+
+                        return itemIsEnabled == enabledValue;
+                    });
+                }
+
+                var taskInfos = tasks.Select(ScheduledTaskHelpers.GetTaskInfo);
+
+                // TODO ToOptimizedResult
+                return Ok(taskInfos);
+            }
+            catch (Exception e)
+            {
+                return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Get task by id.
+        /// </summary>
+        /// <param name="taskId">Task Id.</param>
+        /// <returns>Task Info.</returns>
+        [HttpGet("{TaskID}")]
+        [ProducesResponseType(typeof(TaskInfo), StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
+        public IActionResult GetTask([FromRoute] string taskId)
+        {
+            try
+            {
+                var task = _taskManager.ScheduledTasks.FirstOrDefault(i =>
+                    string.Equals(i.Id, taskId, StringComparison.OrdinalIgnoreCase));
+
+                if (task == null)
+                {
+                    return NotFound();
+                }
+
+                var result = ScheduledTaskHelpers.GetTaskInfo(task);
+                return Ok(result);
+            }
+            catch (Exception e)
+            {
+                return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Start specified task.
+        /// </summary>
+        /// <param name="taskId">Task Id.</param>
+        /// <returns>Status.</returns>
+        [HttpPost("Running/{TaskID}")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
+        public IActionResult StartTask([FromRoute] string taskId)
+        {
+            try
+            {
+                var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
+                    o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
+
+                if (task == null)
+                {
+                    return NotFound();
+                }
+
+                _taskManager.Execute(task, new TaskOptions());
+                return Ok();
+            }
+            catch (Exception e)
+            {
+                return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Stop specified task.
+        /// </summary>
+        /// <param name="taskId">Task Id.</param>
+        /// <returns>Status.</returns>
+        [HttpDelete("Running/{TaskID}")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
+        public IActionResult StopTask([FromRoute] string taskId)
+        {
+            try
+            {
+                var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
+                    o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
+
+                if (task == null)
+                {
+                    return NotFound();
+                }
+
+                _taskManager.Cancel(task);
+                return Ok();
+            }
+            catch (Exception e)
+            {
+                return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Update specified task triggers.
+        /// </summary>
+        /// <param name="taskId">Task Id.</param>
+        /// <param name="triggerInfos">Triggers.</param>
+        /// <returns>Status.</returns>
+        [HttpPost("{TaskID}/Triggers")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
+        public IActionResult UpdateTask([FromRoute] string taskId, [FromBody] TaskTriggerInfo[] triggerInfos)
+        {
+            try
+            {
+                var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
+                    o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
+                if (task == null)
+                {
+                    return NotFound();
+                }
+
+                task.Triggers = triggerInfos;
+                return Ok();
+            }
+            catch (Exception e)
+            {
+                return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
+            }
+        }
+    }
+}

+ 56 - 0
Jellyfin.Server/Converters/LongToStringConverter.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Buffers;
+using System.Buffers.Text;
+using System.Globalization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Jellyfin.Server.Converters
+{
+    /// <summary>
+    /// Long to String JSON converter.
+    /// Javascript does not support 64-bit integers.
+    /// </summary>
+    public class LongToStringConverter : JsonConverter<long>
+    {
+        /// <summary>
+        /// Read JSON string as Long.
+        /// </summary>
+        /// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
+        /// <param name="type">Type.</param>
+        /// <param name="options">Options.</param>
+        /// <returns>Parsed value.</returns>
+        public override long Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
+        {
+            if (reader.TokenType == JsonTokenType.String)
+            {
+                // try to parse number directly from bytes
+                ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
+                if (Utf8Parser.TryParse(span, out long number, out int bytesConsumed) && span.Length == bytesConsumed)
+                {
+                    return number;
+                }
+
+                // try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
+                if (long.TryParse(reader.GetString(), out number))
+                {
+                    return number;
+                }
+            }
+
+            // fallback to default handling
+            return reader.GetInt64();
+        }
+
+        /// <summary>
+        /// Write long to JSON string.
+        /// </summary>
+        /// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
+        /// <param name="value">Value to write.</param>
+        /// <param name="options">Options.</param>
+        public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
+        {
+            writer.WriteStringValue(value.ToString(NumberFormatInfo.InvariantInfo));
+        }
+    }
+}

+ 2 - 0
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs

@@ -4,6 +4,7 @@ using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy;
 using Jellyfin.Api.Auth.RequiresElevationPolicy;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Controllers;
+using Jellyfin.Server.Converters;
 using Microsoft.AspNetCore.Authentication;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.Extensions.DependencyInjection;
@@ -75,6 +76,7 @@ namespace Jellyfin.Server.Extensions
                 {
                     // Setting the naming policy to null leaves the property names as-is when serializing objects to JSON.
                     options.JsonSerializerOptions.PropertyNamingPolicy = null;
+                    options.JsonSerializerOptions.Converters.Add(new LongToStringConverter());
                 })
                 .AddControllersAsServices();
         }