From c059975165997584c26893e3f43d535c9a5f1731 Mon Sep 17 00:00:00 2001 From: genteure Date: Sun, 12 Jun 2022 14:44:29 +0800 Subject: [PATCH] Web: Add file api --- BililiveRecorder.Web/Api/FileController.cs | 99 +++++++++++++++++++ .../Models/Rest/Files/FileApiResult.cs | 23 +++++ .../Models/Rest/Files/FileDto.cs | 12 +++ .../Models/Rest/Files/FileLikeDto.cs | 13 +++ .../Models/Rest/Files/FolderDto.cs | 8 ++ BililiveRecorder.Web/Startup.cs | 3 + 6 files changed, 158 insertions(+) create mode 100644 BililiveRecorder.Web/Api/FileController.cs create mode 100644 BililiveRecorder.Web/Models/Rest/Files/FileApiResult.cs create mode 100644 BililiveRecorder.Web/Models/Rest/Files/FileDto.cs create mode 100644 BililiveRecorder.Web/Models/Rest/Files/FileLikeDto.cs create mode 100644 BililiveRecorder.Web/Models/Rest/Files/FolderDto.cs diff --git a/BililiveRecorder.Web/Api/FileController.cs b/BililiveRecorder.Web/Api/FileController.cs new file mode 100644 index 0000000..bd025b6 --- /dev/null +++ b/BililiveRecorder.Web/Api/FileController.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using BililiveRecorder.Core; +using BililiveRecorder.Web.Models.Rest.Files; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.FileProviders; + +namespace BililiveRecorder.Web.Api +{ + [ApiController, Route("api/[controller]", Name = "[controller] [action]")] + public sealed class FileController : ControllerBase, IDisposable + { + private readonly PhysicalFileProvider? fileProvider; + private bool disposedValue; + + public FileController(IRecorder recorder, BililiveRecorderFileExplorerSettings fileExplorerSettings) + { + if (recorder is null) throw new ArgumentNullException(nameof(recorder)); + if (fileExplorerSettings is null) throw new ArgumentNullException(nameof(fileExplorerSettings)); + if (fileExplorerSettings.Enable) + { + this.fileProvider = new PhysicalFileProvider(recorder.Config.Global.WorkDirectory); + } + } + + /// + /// 获取录播目录文件信息 + /// + /// 路径 + /// + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + public FileApiResult GetFiles([FromQuery] string path) + { + if (this.fileProvider is null || path is null) + return FileApiResult.NotExist; + + var contents = this.fileProvider.GetDirectoryContents(path); + + if (!contents.Exists) + return FileApiResult.NotExist; + + var fileLikes = new List(); + + foreach (var content in contents) + { + try + { + if (!content.Exists) + continue; + + if (content.IsDirectory) + { + fileLikes.Add(new FolderDto + { + Name = content.Name, + LastModified = content.LastModified, + }); + } + else + { + fileLikes.Add(new FileDto + { + Name = content.Name, + LastModified = content.LastModified, + Size = content.Length, + + // Path.Combine 在 Windows 上会用 \ + Url = "/file/" + path.Trim('/') + '/' + content.Name, + }); + } + } + catch (Exception) { } + } + + return new FileApiResult(true, path, fileLikes); + } + + private void Dispose(bool disposing) + { + if (!this.disposedValue) + { + if (disposing) + { + this.fileProvider?.Dispose(); + } + this.disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + this.Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/BililiveRecorder.Web/Models/Rest/Files/FileApiResult.cs b/BililiveRecorder.Web/Models/Rest/Files/FileApiResult.cs new file mode 100644 index 0000000..6302f9f --- /dev/null +++ b/BililiveRecorder.Web/Models/Rest/Files/FileApiResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace BililiveRecorder.Web.Models.Rest.Files +{ + public sealed class FileApiResult + { + public static readonly FileApiResult NotExist = new FileApiResult(false, string.Empty, Array.Empty()); + + public FileApiResult(bool exist, string path, IReadOnlyList files) + { + this.Exist = exist; + this.Path = path ?? throw new ArgumentNullException(nameof(path)); + this.Files = files ?? throw new ArgumentNullException(nameof(files)); + } + + public bool Exist { get; } + + public string Path { get; } + + public IReadOnlyList Files { get; } + } +} diff --git a/BililiveRecorder.Web/Models/Rest/Files/FileDto.cs b/BililiveRecorder.Web/Models/Rest/Files/FileDto.cs new file mode 100644 index 0000000..afda875 --- /dev/null +++ b/BililiveRecorder.Web/Models/Rest/Files/FileDto.cs @@ -0,0 +1,12 @@ +namespace BililiveRecorder.Web.Models.Rest.Files +{ + public sealed class FileDto : FileLikeDto + { + /// false + public override bool IsFolder => false; + + public long Size { get; set; } + + public string Url { get; set; } = string.Empty; + } +} diff --git a/BililiveRecorder.Web/Models/Rest/Files/FileLikeDto.cs b/BililiveRecorder.Web/Models/Rest/Files/FileLikeDto.cs new file mode 100644 index 0000000..74d40e5 --- /dev/null +++ b/BililiveRecorder.Web/Models/Rest/Files/FileLikeDto.cs @@ -0,0 +1,13 @@ +using System; + +namespace BililiveRecorder.Web.Models.Rest.Files +{ + public abstract class FileLikeDto + { + public abstract bool IsFolder { get; } + + public string Name { get; set; } = string.Empty; + + public DateTimeOffset LastModified { get; set; } + } +} diff --git a/BililiveRecorder.Web/Models/Rest/Files/FolderDto.cs b/BililiveRecorder.Web/Models/Rest/Files/FolderDto.cs new file mode 100644 index 0000000..e529870 --- /dev/null +++ b/BililiveRecorder.Web/Models/Rest/Files/FolderDto.cs @@ -0,0 +1,8 @@ +namespace BililiveRecorder.Web.Models.Rest.Files +{ + public sealed class FolderDto : FileLikeDto + { + /// true + public override bool IsFolder => true; + } +} diff --git a/BililiveRecorder.Web/Startup.cs b/BililiveRecorder.Web/Startup.cs index abf0a71..384806d 100644 --- a/BililiveRecorder.Web/Startup.cs +++ b/BililiveRecorder.Web/Startup.cs @@ -98,6 +98,9 @@ namespace BililiveRecorder.Web services .AddSwaggerGen(c => { + c.UseAllOfForInheritance(); + c.UseOneOfForPolymorphism(); + c.SwaggerDoc("brec", new OpenApiInfo { Title = "录播姬 REST API",