mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
FileSystem: Creating an api to retrieve a file mime type
This commit is contained in:
parent
b60046eddc
commit
1a33f38384
@ -2,11 +2,25 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class wrapping a value that will be set after the completion of the task it is related to.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class replace the use of an out parameter on a task since tasks and out can't be combined.
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type of the value</typeparam>
|
||||||
|
public class AsyncRef<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The value that will be set before the completion of the task.
|
||||||
|
/// </summary>
|
||||||
|
public T Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
|
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -42,6 +56,16 @@ namespace Kyoo.Controllers
|
|||||||
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
|
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
|
||||||
/// <returns>A reader to read the file.</returns>
|
/// <returns>A reader to read the file.</returns>
|
||||||
public Task<Stream> GetReader([NotNull] string path);
|
public Task<Stream> GetReader([NotNull] string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read a file present at <paramref name="path"/>. The reader can be used in an arbitrary context.
|
||||||
|
/// To return files from an http endpoint, use <see cref="FileResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file</param>
|
||||||
|
/// <param name="mime">The mime type of the opened file.</param>
|
||||||
|
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
|
||||||
|
/// <returns>A reader to read the file.</returns>
|
||||||
|
public Task<Stream> GetReader([NotNull] string path, AsyncRef<string> mime);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new file at <paramref name="path"></paramref>.
|
/// Create a new file at <paramref name="path"></paramref>.
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
@ -27,13 +26,12 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the local path of the poster of the given item.
|
/// Retrieve the local path of an image of the given item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item to retrieve the poster from.</param>
|
/// <param name="item">The item to retrieve the poster from.</param>
|
||||||
/// <param name="imageID">The ID of the image. See <see cref="Images"/> for values.</param>
|
/// <param name="imageID">The ID of the image. See <see cref="Images"/> for values.</param>
|
||||||
/// <typeparam name="T">The type of the item</typeparam>
|
/// <typeparam name="T">The type of the item</typeparam>
|
||||||
/// <exception cref="NotSupportedException">If the type does not have a poster</exception>
|
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
|
||||||
/// <returns>The path of the poster for the given resource (it might or might not exists).</returns>
|
|
||||||
Task<string> GetImagePath<T>([NotNull] T item, int imageID)
|
Task<string> GetImagePath<T>([NotNull] T item, int imageID)
|
||||||
where T : IThumbnails;
|
where T : IThumbnails;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,15 @@ namespace Kyoo.Controllers
|
|||||||
.GetReader(relativePath);
|
.GetReader(relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<Stream> GetReader(string path, AsyncRef<string> mime)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
throw new ArgumentNullException(nameof(path));
|
||||||
|
return _GetFileSystemForPath(path, out string relativePath)
|
||||||
|
.GetReader(relativePath, mime);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Stream> NewFile(string path)
|
public Task<Stream> NewFile(string path)
|
||||||
{
|
{
|
||||||
@ -181,10 +190,11 @@ namespace Kyoo.Controllers
|
|||||||
Season season => await GetExtraDirectory(season.Show),
|
Season season => await GetExtraDirectory(season.Show),
|
||||||
Episode episode => await GetExtraDirectory(episode.Show),
|
Episode episode => await GetExtraDirectory(episode.Show),
|
||||||
Track track => await GetExtraDirectory(track.Episode),
|
Track track => await GetExtraDirectory(track.Episode),
|
||||||
IResource res => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name, res.Slug),
|
IResource res => Combine(_options.CurrentValue.MetadataPath,
|
||||||
_ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name)
|
typeof(T).Name.ToLowerInvariant(), res.Slug),
|
||||||
|
_ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name.ToLowerInvariant())
|
||||||
};
|
};
|
||||||
return path;
|
return await CreateDirectory(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ using System.IO;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Common.Models.Attributes;
|
using Kyoo.Common.Models.Attributes;
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
@ -44,6 +43,16 @@ namespace Kyoo.Controllers
|
|||||||
HttpClient client = _clientFactory.CreateClient();
|
HttpClient client = _clientFactory.CreateClient();
|
||||||
return client.GetStreamAsync(path);
|
return client.GetStreamAsync(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<Stream> GetReader(string path, AsyncRef<string> mime)
|
||||||
|
{
|
||||||
|
HttpClient client = _clientFactory.CreateClient();
|
||||||
|
HttpResponseMessage response = await client.GetAsync(path);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
mime.Value = response.Content.Headers.ContentType?.MediaType;
|
||||||
|
return await response.Content.ReadAsStreamAsync();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Stream> NewFile(string path)
|
public Task<Stream> NewFile(string path)
|
||||||
|
@ -78,6 +78,16 @@ namespace Kyoo.Controllers
|
|||||||
throw new ArgumentNullException(nameof(path));
|
throw new ArgumentNullException(nameof(path));
|
||||||
return Task.FromResult<Stream>(File.OpenRead(path));
|
return Task.FromResult<Stream>(File.OpenRead(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<Stream> GetReader(string path, AsyncRef<string> mime)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
throw new ArgumentNullException(nameof(path));
|
||||||
|
_provider.TryGetContentType(path, out string mimeValue);
|
||||||
|
mime.Value = mimeValue;
|
||||||
|
return Task.FromResult<Stream>(File.OpenRead(path));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Stream> NewFile(string path)
|
public Task<Stream> NewFile(string path)
|
||||||
|
@ -47,7 +47,9 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using Stream reader = await _files.GetReader(url);
|
AsyncRef<string> mime = new();
|
||||||
|
await using Stream reader = await _files.GetReader(url, mime);
|
||||||
|
// TODO use this mime type to guess the file extension.
|
||||||
await using Stream local = await _files.NewFile(localPath);
|
await using Stream local = await _files.NewFile(localPath);
|
||||||
await reader.CopyToAsync(local);
|
await reader.CopyToAsync(local);
|
||||||
return true;
|
return true;
|
||||||
@ -58,7 +60,7 @@ namespace Kyoo.Controllers
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
public async Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
||||||
where T : IThumbnails
|
where T : IThumbnails
|
||||||
@ -74,28 +76,32 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
foreach ((int id, string image) in item.Images.Where(x => x.Value != null))
|
foreach ((int id, string image) in item.Images.Where(x => x.Value != null))
|
||||||
{
|
{
|
||||||
string localPath = await GetImagePath(item, id);
|
string localPath = await _GetPrivateImagePath(item, id);
|
||||||
if (alwaysDownload || !await _files.Exists(localPath))
|
if (alwaysDownload || !await _files.Exists(localPath))
|
||||||
ret |= await _DownloadImage(image, localPath, $"The image n°{id} of {name}");
|
ret |= await _DownloadImage(image, localPath, $"The image n°{id} of {name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public async Task<string> GetImagePath<T>(T item, int imageID)
|
/// Retrieve the local path of an image of the given item <b>without an extension</b>.
|
||||||
where T : IThumbnails
|
/// </summary>
|
||||||
|
/// <param name="item">The item to retrieve the poster from.</param>
|
||||||
|
/// <param name="imageID">The ID of the image. See <see cref="Images"/> for values.</param>
|
||||||
|
/// <typeparam name="T">The type of the item</typeparam>
|
||||||
|
/// <returns>The path of the image for the given resource, <b>even if it does not exists</b></returns>
|
||||||
|
private async Task<string> _GetPrivateImagePath<T>(T item, int imageID)
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
throw new ArgumentNullException(nameof(item));
|
throw new ArgumentNullException(nameof(item));
|
||||||
// TODO handle extensions
|
|
||||||
string imageName = imageID switch
|
string imageName = imageID switch
|
||||||
{
|
{
|
||||||
Images.Poster => "poster.jpg",
|
Images.Poster => "poster",
|
||||||
Images.Logo => "logo.jpg",
|
Images.Logo => "logo",
|
||||||
Images.Thumbnail => "thumbnail.jpg",
|
Images.Thumbnail => "thumbnail",
|
||||||
Images.Trailer => "trailer.mp4",
|
Images.Trailer => "trailer",
|
||||||
_ => $"{imageID}.jpg"
|
_ => $"{imageID}"
|
||||||
};
|
};
|
||||||
|
|
||||||
imageName = item switch
|
imageName = item switch
|
||||||
@ -108,5 +114,16 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
return _files.Combine(await _files.GetExtraDirectory(item), imageName);
|
return _files.Combine(await _files.GetExtraDirectory(item), imageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<string> GetImagePath<T>(T item, int imageID)
|
||||||
|
where T : IThumbnails
|
||||||
|
{
|
||||||
|
string basePath = await _GetPrivateImagePath(item, imageID);
|
||||||
|
string directory = Path.GetDirectoryName(basePath);
|
||||||
|
string baseFile = Path.GetFileName(basePath);
|
||||||
|
return (await _files.ListFiles(directory!))
|
||||||
|
.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == baseFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user