// Kyoo - A portable and vast media library solution. // Copyright (c) Kyoo. // // See AUTHORS.md and LICENSE file in the project root for full license information. // // Kyoo is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // Kyoo is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Core.Models.Options; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Options; namespace Kyoo.Core.Controllers { /// /// A for the local filesystem (using System.IO). /// [FileSystemMetadata(new[] { "", "file" }, StripScheme = true)] public class LocalFileSystem : IFileSystem { /// /// An extension provider to get content types from files extensions. /// private readonly IContentTypeProvider _provider; /// /// Options to check if the metadata should be kept in the show directory or in a kyoo's directory. /// private readonly IOptionsMonitor _options; /// /// Create a new with the specified options. /// /// The options to use. /// An extension provider to get content types from files extensions. public LocalFileSystem(IOptionsMonitor options, IContentTypeProvider provider) { _options = options; _provider = provider; } /// /// Get the content type of a file using it's extension. /// /// The path of the file /// The extension of the file is not known. /// The content type of the file private string _GetContentType(string path) { if (_provider.TryGetContentType(path, out string contentType)) return contentType; throw new NotImplementedException($"Can't get the content type of the file at: {path}"); } /// public IActionResult FileResult(string path, bool rangeSupport = false, string type = null) { if (path == null) return new NotFoundResult(); if (!File.Exists(path)) return new NotFoundResult(); return new PhysicalFileResult(Path.GetFullPath(path), type ?? _GetContentType(path)) { EnableRangeProcessing = rangeSupport }; } /// public Task GetReader(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); return Task.FromResult(File.OpenRead(path)); } /// public Task GetReader(string path, AsyncRef mime) { if (path == null) throw new ArgumentNullException(nameof(path)); _provider.TryGetContentType(path, out string mimeValue); mime.Value = mimeValue; return Task.FromResult(File.OpenRead(path)); } /// public Task NewFile(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); return Task.FromResult(File.Create(path)); } /// public Task CreateDirectory(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); Directory.CreateDirectory(path); return Task.FromResult(path); } /// public string Combine(params string[] paths) { return Path.Combine(paths); } /// public Task> ListFiles(string path, SearchOption options = SearchOption.TopDirectoryOnly) { if (path == null) throw new ArgumentNullException(nameof(path)); string[] ret = Directory.Exists(path) ? Directory.GetFiles(path, "*", options) : Array.Empty(); return Task.FromResult>(ret); } /// public Task Exists(string path) { return Task.FromResult(File.Exists(path) || Directory.Exists(path)); } /// public Task GetExtraDirectory(T resource) { if (!_options.CurrentValue.MetadataInShow) return Task.FromResult(null); return Task.FromResult(resource switch { Show show => Combine(show.Path, "Extra"), Season season => Combine(season.Show.Path, "Extra"), Episode episode => Combine(episode.Show.Path, "Extra"), Track track => Combine(track.Episode.Show.Path, "Extra"), _ => null }); } } }