diff --git a/Kyoo.Common/Controllers/IFileSystem.cs b/Kyoo.Common/Controllers/IFileSystem.cs
index f0702e04..92e951b7 100644
--- a/Kyoo.Common/Controllers/IFileSystem.cs
+++ b/Kyoo.Common/Controllers/IFileSystem.cs
@@ -2,11 +2,25 @@ using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using JetBrains.Annotations;
-using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
{
+ ///
+ /// A class wrapping a value that will be set after the completion of the task it is related to.
+ ///
+ ///
+ /// This class replace the use of an out parameter on a task since tasks and out can't be combined.
+ ///
+ /// The type of the value
+ public class AsyncRef
+ {
+ ///
+ /// The value that will be set before the completion of the task.
+ ///
+ public T Value { get; set; }
+ }
+
///
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
///
@@ -42,6 +56,16 @@ namespace Kyoo.Controllers
/// If the file could not be found.
/// A reader to read the file.
public Task GetReader([NotNull] string path);
+
+ ///
+ /// Read a file present at . The reader can be used in an arbitrary context.
+ /// To return files from an http endpoint, use .
+ ///
+ /// The path of the file
+ /// The mime type of the opened file.
+ /// If the file could not be found.
+ /// A reader to read the file.
+ public Task GetReader([NotNull] string path, AsyncRef mime);
///
/// Create a new file at .
diff --git a/Kyoo.Common/Controllers/IThumbnailsManager.cs b/Kyoo.Common/Controllers/IThumbnailsManager.cs
index aac09210..61fe5345 100644
--- a/Kyoo.Common/Controllers/IThumbnailsManager.cs
+++ b/Kyoo.Common/Controllers/IThumbnailsManager.cs
@@ -1,5 +1,4 @@
-using System;
-using Kyoo.Models;
+using Kyoo.Models;
using System.Threading.Tasks;
using JetBrains.Annotations;
@@ -27,13 +26,12 @@ namespace Kyoo.Controllers
///
- /// Retrieve the local path of the poster of the given item.
+ /// Retrieve the local path of an image of the given item.
///
/// The item to retrieve the poster from.
/// The ID of the image. See for values.
/// The type of the item
- /// If the type does not have a poster
- /// The path of the poster for the given resource (it might or might not exists).
+ /// The path of the image for the given resource or null if it does not exists.
Task GetImagePath([NotNull] T item, int imageID)
where T : IThumbnails;
}
diff --git a/Kyoo/Controllers/FileSystems/FileSystemComposite.cs b/Kyoo/Controllers/FileSystems/FileSystemComposite.cs
index 20a7f67d..b3f4f66a 100644
--- a/Kyoo/Controllers/FileSystems/FileSystemComposite.cs
+++ b/Kyoo/Controllers/FileSystems/FileSystemComposite.cs
@@ -107,6 +107,15 @@ namespace Kyoo.Controllers
.GetReader(relativePath);
}
+ ///
+ public Task GetReader(string path, AsyncRef mime)
+ {
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+ return _GetFileSystemForPath(path, out string relativePath)
+ .GetReader(relativePath, mime);
+ }
+
///
public Task NewFile(string path)
{
@@ -181,10 +190,11 @@ namespace Kyoo.Controllers
Season season => await GetExtraDirectory(season.Show),
Episode episode => await GetExtraDirectory(episode.Show),
Track track => await GetExtraDirectory(track.Episode),
- IResource res => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name, res.Slug),
- _ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name)
+ IResource res => Combine(_options.CurrentValue.MetadataPath,
+ typeof(T).Name.ToLowerInvariant(), res.Slug),
+ _ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name.ToLowerInvariant())
};
- return path;
+ return await CreateDirectory(path);
}
}
}
\ No newline at end of file
diff --git a/Kyoo/Controllers/FileSystems/HttpFileSystem.cs b/Kyoo/Controllers/FileSystems/HttpFileSystem.cs
index 5eeebbc2..82409cdc 100644
--- a/Kyoo/Controllers/FileSystems/HttpFileSystem.cs
+++ b/Kyoo/Controllers/FileSystems/HttpFileSystem.cs
@@ -4,7 +4,6 @@ using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Kyoo.Common.Models.Attributes;
-using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
@@ -44,6 +43,16 @@ namespace Kyoo.Controllers
HttpClient client = _clientFactory.CreateClient();
return client.GetStreamAsync(path);
}
+
+ ///
+ public async Task GetReader(string path, AsyncRef 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();
+ }
///
public Task NewFile(string path)
diff --git a/Kyoo/Controllers/FileSystems/LocalFileSystem.cs b/Kyoo/Controllers/FileSystems/LocalFileSystem.cs
index 71dac41d..18d887a0 100644
--- a/Kyoo/Controllers/FileSystems/LocalFileSystem.cs
+++ b/Kyoo/Controllers/FileSystems/LocalFileSystem.cs
@@ -78,6 +78,16 @@ namespace Kyoo.Controllers
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)
diff --git a/Kyoo/Controllers/ThumbnailsManager.cs b/Kyoo/Controllers/ThumbnailsManager.cs
index 142ee236..b56625bd 100644
--- a/Kyoo/Controllers/ThumbnailsManager.cs
+++ b/Kyoo/Controllers/ThumbnailsManager.cs
@@ -47,7 +47,9 @@ namespace Kyoo.Controllers
try
{
- await using Stream reader = await _files.GetReader(url);
+ AsyncRef 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 reader.CopyToAsync(local);
return true;
@@ -58,7 +60,7 @@ namespace Kyoo.Controllers
return false;
}
}
-
+
///
public async Task DownloadImages(T item, bool alwaysDownload = false)
where T : IThumbnails
@@ -74,28 +76,32 @@ namespace Kyoo.Controllers
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))
ret |= await _DownloadImage(image, localPath, $"The image n°{id} of {name}");
}
return ret;
}
-
- ///
- public async Task GetImagePath(T item, int imageID)
- where T : IThumbnails
+
+ ///
+ /// Retrieve the local path of an image of the given item without an extension.
+ ///
+ /// The item to retrieve the poster from.
+ /// The ID of the image. See for values.
+ /// The type of the item
+ /// The path of the image for the given resource, even if it does not exists
+ private async Task _GetPrivateImagePath(T item, int imageID)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
- // TODO handle extensions
string imageName = imageID switch
{
- Images.Poster => "poster.jpg",
- Images.Logo => "logo.jpg",
- Images.Thumbnail => "thumbnail.jpg",
- Images.Trailer => "trailer.mp4",
- _ => $"{imageID}.jpg"
+ Images.Poster => "poster",
+ Images.Logo => "logo",
+ Images.Thumbnail => "thumbnail",
+ Images.Trailer => "trailer",
+ _ => $"{imageID}"
};
imageName = item switch
@@ -108,5 +114,16 @@ namespace Kyoo.Controllers
return _files.Combine(await _files.GetExtraDirectory(item), imageName);
}
+
+ ///
+ public async Task GetImagePath(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);
+ }
}
}