// 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
});
}
}
}