diff --git a/.editorconfig b/.editorconfig
index 01763e5f..7b812979 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -89,3 +89,5 @@ resharper_xmldoc_attribute_indent = align_by_first_attribute
resharper_xmldoc_indent_child_elements = RemoveIndent
resharper_xmldoc_indent_text = RemoveIndent
+# Waiting for https://github.com/dotnet/roslyn/issues/44596 to get fixed.
+# file_header_template = Kyoo - A portable and vast media library solution.\nCopyright (c) Kyoo.\n\nSee AUTHORS.md and LICENSE file in the project root for full license information.\n\nKyoo is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\nany later version.\n\nKyoo is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Kyoo. If not, see .
diff --git a/AUTHORS.md b/AUTHORS.md
index b7f88d9d..ad32290a 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -1,4 +1,4 @@
# Authors
-Alphabetical order by first name.
+Ordered by the date of the first commit.
* Zoe Roux ([@AnonymusRaccoon](http://github.com/AnonymusRaccoon))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3e36365a..6dbaad61 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -25,6 +25,7 @@ Here are a few things you can do that will increase the likelihood of your pull
## Resources
+- [Why should you indent with tabs](https://www.reddit.com/r/javascript/comments/c8drjo/nobody_talks_about_the_real_reason_to_use_tabs/)
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
- [GitHub Help](https://docs.github.com/en)
diff --git a/Kyoo.sln b/Kyoo.sln
index faab841f..c240e473 100644
--- a/Kyoo.sln
+++ b/Kyoo.sln
@@ -23,6 +23,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.WindowsTrait", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Console", "src\Kyoo.Host.Console\Kyoo.Host.Console.csproj", "{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FEAE1B0E-D797-470F-9030-0EF743575ECC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Databases", "Databases", "{865461CA-EC06-4B42-91CF-8723B0A9BB67}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{C569FF25-7E01-484C-9F72-5B99845AD94B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -81,5 +91,19 @@ Global
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC}
+ {BAB270D4-E0EA-4329-BA65-512FDAB01001} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
+ {D06BF829-23F5-40F3-A62D-627D9F4B4D6C} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
+ {6F91B645-F785-46BB-9C4F-1EFC83E489B6} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
+ {3213C96D-0BF3-460B-A8B5-B9977229408A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
+ {6515380E-1E57-42DA-B6E3-E1C8A848818A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
+ {D8658BEA-8949-45AC-BEBB-A4FFC4F800F5} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
+ {98851001-40DD-46A6-94B3-2F8D90722076} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
EndGlobalSection
EndGlobal
diff --git a/icons/banner.png b/icons/banner.png
new file mode 100644
index 00000000..db5e97cd
Binary files /dev/null and b/icons/banner.png differ
diff --git a/icons/icon-128x128.png b/icons/icon-128x128.png
new file mode 100644
index 00000000..f602aaaa
Binary files /dev/null and b/icons/icon-128x128.png differ
diff --git a/icons/icon-16x16.png b/icons/icon-16x16.png
new file mode 100644
index 00000000..f0ecbd81
Binary files /dev/null and b/icons/icon-16x16.png differ
diff --git a/icons/icon-256x256.ico b/icons/icon-256x256.ico
new file mode 100644
index 00000000..8a6ef232
Binary files /dev/null and b/icons/icon-256x256.ico differ
diff --git a/icons/icon-256x256.png b/icons/icon-256x256.png
new file mode 100644
index 00000000..a395f0fe
Binary files /dev/null and b/icons/icon-256x256.png differ
diff --git a/icons/icon-32x32.png b/icons/icon-32x32.png
new file mode 100644
index 00000000..b5944473
Binary files /dev/null and b/icons/icon-32x32.png differ
diff --git a/icons/icon-64x64.png b/icons/icon-64x64.png
new file mode 100644
index 00000000..ad7d28e9
Binary files /dev/null and b/icons/icon-64x64.png differ
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index b9d5b35c..b2300460 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,4 +1,24 @@
+
+ Kyoo
+ Kyoo
+ Copyright (c) Kyoo
+ true
+ GPL-3.0-or-later
+ true
+
+ https://github.com/AnonymusRaccoon/Kyoo
+ git
+ true
+ https://github.com/AnonymusRaccoon/Kyoo
+
+ 1.0.0
+ true
+ snupkg
+
+ $(MSBuildThisFileDirectory)../icons/icon-256x256.ico
+
+
truetrue
@@ -11,6 +31,10 @@
true
+
+
+
+
@@ -21,7 +45,6 @@
true
- CS1591;SA1600;SA1601true$(MSBuildThisFileDirectory)../Kyoo.ruleset
diff --git a/src/Kyoo.Abstractions/Controllers/IFileSystem.cs b/src/Kyoo.Abstractions/Controllers/IFileSystem.cs
index a8cfd96c..f70a577b 100644
--- a/src/Kyoo.Abstractions/Controllers/IFileSystem.cs
+++ b/src/Kyoo.Abstractions/Controllers/IFileSystem.cs
@@ -31,8 +31,6 @@ namespace Kyoo.Abstractions.Controllers
///
public interface IFileSystem
{
- // TODO find a way to handle Transmux/Transcode with this system.
-
///
/// Used for http queries returning a file. This should be used to return local files
/// or proxy them from a distant server.
@@ -51,7 +49,7 @@ namespace Kyoo.Abstractions.Controllers
/// If the type is not specified, it will be deduced automatically (from the extension or by sniffing the file).
///
/// An representing the file returned.
- public IActionResult FileResult([CanBeNull] string path, bool rangeSupport = false, string type = null);
+ IActionResult FileResult([CanBeNull] string path, bool rangeSupport = false, string type = null);
///
/// Read a file present at . The reader can be used in an arbitrary context.
@@ -60,7 +58,7 @@ namespace Kyoo.Abstractions.Controllers
/// The path of the file
/// If the file could not be found.
/// A reader to read the file.
- public Task GetReader([NotNull] string path);
+ Task GetReader([NotNull] string path);
///
/// Read a file present at . The reader can be used in an arbitrary context.
@@ -70,28 +68,28 @@ namespace Kyoo.Abstractions.Controllers
/// 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);
+ Task GetReader([NotNull] string path, AsyncRef mime);
///
/// Create a new file at .
///
/// The path of the new file.
/// A writer to write to the new file.
- public Task NewFile([NotNull] string path);
+ Task NewFile([NotNull] string path);
///
/// Create a new directory at the given path
///
/// The path of the directory
/// The path of the newly created directory is returned.
- public Task CreateDirectory([NotNull] string path);
+ Task CreateDirectory([NotNull] string path);
///
/// Combine multiple paths.
///
/// The paths to combine
/// The combined path.
- public string Combine(params string[] paths);
+ string Combine(params string[] paths);
///
/// List files in a directory.
@@ -99,7 +97,7 @@ namespace Kyoo.Abstractions.Controllers
/// The path of the directory
/// Should the search be recursive or not.
/// A list of files's path.
- public Task> ListFiles([NotNull] string path,
+ Task> ListFiles([NotNull] string path,
SearchOption options = SearchOption.TopDirectoryOnly);
///
@@ -107,7 +105,7 @@ namespace Kyoo.Abstractions.Controllers
///
/// The path to check
/// True if the path exists, false otherwise
- public Task Exists([NotNull] string path);
+ Task Exists([NotNull] string path);
///
/// Get the extra directory of a resource .
@@ -117,6 +115,25 @@ namespace Kyoo.Abstractions.Controllers
/// The resource to proceed
/// The type of the resource.
/// The extra directory of the resource.
- public Task GetExtraDirectory([NotNull] T resource);
+ Task GetExtraDirectory([NotNull] T resource);
+
+ ///
+ /// Retrieve tracks for a specific episode.
+ /// Subtitles, chapters and fonts should also be extracted and cached when calling this method.
+ ///
+ /// The episode to retrieve tracks for.
+ /// Should the cache be invalidated and subtitles and others be re-extracted?
+ /// The list of tracks available for this episode.
+ Task> ExtractInfos([NotNull] Episode episode, bool reExtract);
+
+ ///
+ /// Transmux the selected episode to hls.
+ ///
+ /// The episode to transmux.
+ /// The master file (m3u8) of the transmuxed hls file.
+ IActionResult Transmux([NotNull] Episode episode);
+
+ // Maybe add options for to select the codec.
+ // IActionResult Transcode(Episode episode);
}
}
diff --git a/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
index f4218760..3b1a1b7f 100644
--- a/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
+++ b/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
@@ -200,10 +200,11 @@ namespace Kyoo.Abstractions.Controllers
/// Get the resource by a filter function or null if it is not found.
///
/// The filter function.
+ /// A custom sort method to handle cases where multiples items match the filters.
/// The type of the resource
/// The first resource found that match the where function
[ItemCanBeNull]
- Task GetOrDefault(Expression> where)
+ Task GetOrDefault(Expression> where, Sort sortBy = default)
where T : class, IResource;
///
@@ -317,6 +318,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No library exist with the given ID.
/// A list of items that match every filters
Task> GetItemsFromLibrary(int id,
Expression> where = null,
@@ -330,6 +332,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No library exist with the given ID.
/// A list of items that match every filters
Task> GetItemsFromLibrary(int id,
[Optional] Expression> where,
@@ -344,6 +347,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No library exist with the given slug.
/// A list of items that match every filters
Task> GetItemsFromLibrary(string slug,
Expression> where = null,
@@ -357,6 +361,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No library exist with the given slug.
/// A list of items that match every filters
Task> GetItemsFromLibrary(string slug,
[Optional] Expression> where,
@@ -371,6 +376,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetPeopleFromShow(int showID,
Expression> where = null,
@@ -384,6 +390,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetPeopleFromShow(int showID,
[Optional] Expression> where,
@@ -398,6 +405,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetPeopleFromShow(string showSlug,
Expression> where = null,
@@ -411,6 +419,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetPeopleFromShow(string showSlug,
[Optional] Expression> where,
@@ -425,6 +434,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetRolesFromPeople(int id,
Expression> where = null,
@@ -438,6 +448,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetRolesFromPeople(int id,
[Optional] Expression> where,
@@ -452,6 +463,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetRolesFromPeople(string slug,
Expression> where = null,
@@ -465,6 +477,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetRolesFromPeople(string slug,
[Optional] Expression> where,
diff --git a/src/Kyoo.Abstractions/Controllers/IRepository.cs b/src/Kyoo.Abstractions/Controllers/IRepository.cs
index 805de8ec..1d996e97 100644
--- a/src/Kyoo.Abstractions/Controllers/IRepository.cs
+++ b/src/Kyoo.Abstractions/Controllers/IRepository.cs
@@ -81,9 +81,10 @@ namespace Kyoo.Abstractions.Controllers
/// Get the first resource that match the predicate or null if it is not found.
///
/// A predicate to filter the resource.
+ /// A custom sort method to handle cases where multiples items match the filters.
/// The resource found
[ItemCanBeNull]
- Task GetOrDefault(Expression> where);
+ Task GetOrDefault(Expression> where, Sort sortBy = default);
///
/// Search for resources.
@@ -179,7 +180,6 @@ namespace Kyoo.Abstractions.Controllers
/// Delete all resources that match the predicate.
///
/// A predicate to filter resources to delete. Every resource that match this will be deleted.
- /// If the item is not found
/// A representing the asynchronous operation.
Task DeleteAll([NotNull] Expression> where);
}
@@ -264,6 +264,8 @@ namespace Kyoo.Abstractions.Controllers
///
public interface IEpisodeRepository : IRepository
{
+ // TODO replace the next methods with extension methods.
+
///
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
///
@@ -343,6 +345,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No library exist with the given ID.
/// A list of items that match every filters
public Task> GetFromLibrary(int id,
Expression> where = null,
@@ -356,6 +359,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No library exist with the given ID.
/// A list of items that match every filters
public Task> GetFromLibrary(int id,
[Optional] Expression> where,
@@ -370,6 +374,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No library exist with the given slug.
/// A list of items that match every filters
public Task> GetFromLibrary(string slug,
Expression> where = null,
@@ -383,6 +388,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No library exist with the given slug.
/// A list of items that match every filters
public Task> GetFromLibrary(string slug,
[Optional] Expression> where,
@@ -418,6 +424,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetFromShow(int showID,
Expression> where = null,
@@ -431,6 +438,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetFromShow(int showID,
[Optional] Expression> where,
@@ -445,6 +453,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetFromShow(string showSlug,
Expression> where = null,
@@ -458,6 +467,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetFromShow(string showSlug,
[Optional] Expression> where,
@@ -472,6 +482,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetFromPeople(int id,
Expression> where = null,
@@ -485,6 +496,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given ID.
/// A list of items that match every filters
Task> GetFromPeople(int id,
[Optional] Expression> where,
@@ -499,6 +511,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// Sort information (sort order and sort by)
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetFromPeople(string slug,
Expression> where = null,
@@ -512,6 +525,7 @@ namespace Kyoo.Abstractions.Controllers
/// A filter function
/// A sort by method
/// How many items to return and where to start
+ /// No exist with the given slug.
/// A list of items that match every filters
Task> GetFromPeople(string slug,
[Optional] Expression> where,
diff --git a/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj b/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
index 60af7d84..3bc50076 100644
--- a/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
+++ b/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
@@ -1,20 +1,9 @@
-
net5.0
- Kyoo.Abstractions
- Zoe Roux
- Base package to create plugins for Kyoo.
- https://github.com/AnonymusRaccoon/Kyoo
- true
- https://github.com/AnonymusRaccoon/Kyoo
- SDG
- GPL-3.0-or-later
- true
- 1.0.0
- true
- snupkgdefault
+ Kyoo.Abstractions
+ Base package to create plugins for Kyoo.Kyoo.Abstractions
@@ -24,8 +13,6 @@
-
-
diff --git a/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs
new file mode 100644
index 00000000..cd946714
--- /dev/null
+++ b/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs
@@ -0,0 +1,55 @@
+// 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 JetBrains.Annotations;
+
+namespace Kyoo.Abstractions.Models.Attributes
+{
+ ///
+ /// An attribute to specify on apis to specify it's documentation's name and category.
+ /// If this is applied on a method, the specified method will be exploded from the controller's page and be
+ /// included on the specified tag page.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+ public class ApiDefinitionAttribute : Attribute
+ {
+ ///
+ /// The public name of this api.
+ ///
+ [NotNull] public string Name { get; }
+
+ ///
+ /// The name of the group in witch this API is. You can also specify a custom sort order using the following
+ /// format: order:name. Everything before the first : will be removed but kept for
+ /// th alphabetical ordering.
+ ///
+ public string Group { get; set; }
+
+ ///
+ /// Create a new .
+ ///
+ /// The name of the api that will be used on the documentation page.
+ public ApiDefinitionAttribute([NotNull] string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException(nameof(name));
+ Name = name;
+ }
+ }
+}
diff --git a/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs
index 58e6366a..bac1edec 100644
--- a/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs
+++ b/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs
@@ -39,6 +39,11 @@ namespace Kyoo.Abstractions.Models.Permissions
///
public Kind Kind { get; }
+ ///
+ /// The group of this permission.
+ ///
+ public Group Group { get; set; }
+
///
/// Ask a permission to run an action.
///
@@ -49,14 +54,9 @@ namespace Kyoo.Abstractions.Models.Permissions
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
/// lead to unspecified behaviors.
///
- ///
- /// The type of the action
- /// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
- ///
+ /// The type of the action
public PartialPermissionAttribute(string type)
{
- if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
- type = type[..^3];
Type = type.ToLower();
}
diff --git a/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs
index 2cf85d2f..cb17020c 100644
--- a/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs
+++ b/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs
@@ -91,17 +91,16 @@ namespace Kyoo.Abstractions.Models.Permissions
///
///
/// The type of the action
- /// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
///
- /// The kind of permission needed.
+ ///
+ /// The kind of permission needed.
+ ///
///
/// The group of this permission (allow grouped permission like overall.read
/// for all read permissions of this group).
///
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
{
- if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
- type = type[..^3];
Type = type.ToLower();
Kind = permission;
Group = group;
diff --git a/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeAsAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeAsAttribute.cs
deleted file mode 100644
index 6e2a8983..00000000
--- a/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeAsAttribute.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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;
-
-namespace Kyoo.Abstractions.Models.Attributes
-{
- ///
- /// Change the way the field is serialized. It allow one to use a string format like formatting instead of the default value.
- /// This can be disabled for a request by setting the "internal" query string parameter to true.
- ///
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
- public class SerializeAsAttribute : Attribute
- {
- ///
- /// The format string to use.
- ///
- public string Format { get; }
-
- ///
- /// Create a new with the selected format.
- ///
- ///
- /// The format string can contains any property within {}. It will be replaced by the actual value of the property.
- /// You can also use the special value {HOST} that will put the webhost address.
- ///
- ///
- /// The show's poster serialized uses this format string: {HOST}/api/shows/{Slug}/poster
- ///
- /// The format to use
- public SerializeAsAttribute(string format)
- {
- Format = format;
- }
- }
-}
diff --git a/src/Kyoo.Abstractions/Models/ConfigurationReference.cs b/src/Kyoo.Abstractions/Models/ConfigurationReference.cs
index 2272612f..635bbb97 100644
--- a/src/Kyoo.Abstractions/Models/ConfigurationReference.cs
+++ b/src/Kyoo.Abstractions/Models/ConfigurationReference.cs
@@ -105,9 +105,17 @@ namespace Kyoo.Abstractions.Models
return CreateReference(path, typeof(T));
}
+ ///
+ /// Return a meaning that the given path is of any type.
+ /// It means that the type can't be edited.
+ ///
+ ///
+ /// The path that will be untyped (separated by ':' or "__". If empty, it will start at root).
+ ///
+ /// A configuration reference representing a path of any type.
public static ConfigurationReference CreateUntyped(string path)
{
- return new(path, null);
+ return new ConfigurationReference(path, null);
}
}
}
diff --git a/src/Kyoo.Abstractions/Models/LibraryItem.cs b/src/Kyoo.Abstractions/Models/LibraryItem.cs
index c572f6a4..fd9a5b85 100644
--- a/src/Kyoo.Abstractions/Models/LibraryItem.cs
+++ b/src/Kyoo.Abstractions/Models/LibraryItem.cs
@@ -18,8 +18,8 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq.Expressions;
-using Kyoo.Abstractions.Models.Attributes;
namespace Kyoo.Abstractions.Models
{
@@ -34,7 +34,8 @@ namespace Kyoo.Abstractions.Models
Show,
///
- /// The is a Movie (a with equals to true).
+ /// The is a Movie (a with
+ /// equals to true).
///
Movie,
@@ -48,7 +49,7 @@ namespace Kyoo.Abstractions.Models
/// A type union between and .
/// This is used to list content put inside a library.
///
- public class LibraryItem : IResource, IThumbnails
+ public class LibraryItem : CustomTypeDescriptor, IResource, IThumbnails
{
///
public int ID { get; set; }
@@ -86,14 +87,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this item's poster.
- /// By default, the http path for this poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")]
- public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
-
///
/// The type of this item (ether a collection, a show or a movie).
///
@@ -169,5 +162,11 @@ namespace Kyoo.Abstractions.Models
Images = x.Images,
Type = ItemType.Collection
};
+
+ ///
+ public override string GetClassName()
+ {
+ return Type.ToString();
+ }
}
}
diff --git a/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/src/Kyoo.Abstractions/Models/Resources/Collection.cs
index 5f48fee1..101781f4 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Collection.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Collection.cs
@@ -16,7 +16,6 @@
// 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 Kyoo.Abstractions.Models.Attributes;
@@ -42,15 +41,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this poster.
- /// By default, the http path for this poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/collection/{Slug}/poster")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
-
///
/// The description of this collection.
///
diff --git a/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/src/Kyoo.Abstractions/Models/Resources/Episode.cs
index 83f82b08..42e9ecee 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Episode.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Episode.cs
@@ -127,15 +127,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this episode's thumbnail.
- /// By default, the http path for the thumbnail is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/episodes/{Slug}/thumbnail")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Thumb => Images?.GetValueOrDefault(Models.Images.Thumbnail);
-
///
/// The title of this episode.
///
diff --git a/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
index e2d83e78..6a84977f 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs
@@ -33,9 +33,8 @@ namespace Kyoo.Abstractions.Models
///
/// An arbitrary index should not be used, instead use indexes from
///
+ /// {"0": "example.com/dune/poster"}
public Dictionary Images { get; set; }
-
- // TODO remove Posters properties add them via the json serializer for every IThumbnails
}
///
@@ -63,5 +62,17 @@ namespace Kyoo.Abstractions.Models
/// A video of a few minutes that tease the content.
///
public const int Trailer = 3;
+
+ ///
+ /// Retrieve the name of an image using it's ID. It is also used by the serializer to retrieve all named images.
+ /// If a plugin adds a new image type, it should add it's value and name here to allow the serializer to add it.
+ ///
+ public static Dictionary ImageName { get; } = new()
+ {
+ [Poster] = nameof(Poster),
+ [Thumbnail] = nameof(Thumbnail),
+ [Logo] = nameof(Logo),
+ [Trailer] = nameof(Trailer)
+ };
}
}
diff --git a/src/Kyoo.Abstractions/Models/Resources/People.cs b/src/Kyoo.Abstractions/Models/Resources/People.cs
index e1070545..71f9012d 100644
--- a/src/Kyoo.Abstractions/Models/Resources/People.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/People.cs
@@ -16,7 +16,6 @@
// 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 Kyoo.Abstractions.Models.Attributes;
@@ -41,15 +40,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this poster.
- /// By default, the http path for this poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/people/{Slug}/poster")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
-
///
[EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
diff --git a/src/Kyoo.Abstractions/Models/Resources/Provider.cs b/src/Kyoo.Abstractions/Models/Resources/Provider.cs
index 74401045..e1c10de3 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Provider.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Provider.cs
@@ -16,7 +16,6 @@
// 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 Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
@@ -44,15 +43,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this provider's logo.
- /// By default, the http path for this logo is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/providers/{Slug}/logo")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Logo => Images?.GetValueOrDefault(Models.Images.Logo);
-
///
/// The list of libraries that uses this provider.
///
diff --git a/src/Kyoo.Abstractions/Models/Resources/Season.cs b/src/Kyoo.Abstractions/Models/Resources/Season.cs
index f219f483..29d22d44 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Season.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Season.cs
@@ -98,15 +98,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this poster.
- /// By default, the http path for this poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/seasons/{Slug}/thumb")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
-
///
[EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
diff --git a/src/Kyoo.Abstractions/Models/Resources/Show.cs b/src/Kyoo.Abstractions/Models/Resources/Show.cs
index 87e00052..97061446 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Show.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Show.cs
@@ -82,33 +82,6 @@ namespace Kyoo.Abstractions.Models
///
public Dictionary Images { get; set; }
- ///
- /// The path of this show's poster.
- /// By default, the http path for this poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/shows/{Slug}/poster")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
-
- ///
- /// The path of this show's logo.
- /// By default, the http path for this logo is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/shows/{Slug}/logo")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Logo => Images?.GetValueOrDefault(Models.Images.Logo);
-
- ///
- /// The path of this show's backdrop.
- /// By default, the http path for this backdrop is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/shows/{Slug}/backdrop")]
- [Obsolete("Use Images instead of this, this is only kept for the API response.")]
- public string Backdrop => Images?.GetValueOrDefault(Models.Images.Thumbnail);
-
///
/// True if this show represent a movie, false otherwise.
///
diff --git a/src/Kyoo.Abstractions/Models/Resources/Track.cs b/src/Kyoo.Abstractions/Models/Resources/Track.cs
index e6d5d7e1..8e41c7ee 100644
--- a/src/Kyoo.Abstractions/Models/Resources/Track.cs
+++ b/src/Kyoo.Abstractions/Models/Resources/Track.cs
@@ -52,7 +52,7 @@ namespace Kyoo.Abstractions.Models
Subtitle = 3,
///
- /// The stream is an attachement (a font, an image or something else).
+ /// The stream is an attachment (a font, an image or something else).
/// Only fonts are handled by kyoo but they are not saved to the database.
///
Attachment = 4
@@ -73,7 +73,7 @@ namespace Kyoo.Abstractions.Models
{
string type = Type.ToString().ToLower();
string index = TrackIndex != 0 ? $"-{TrackIndex}" : string.Empty;
- string episode = EpisodeSlug ?? Episode?.Slug ?? EpisodeID.ToString();
+ string episode = _episodeSlug ?? Episode?.Slug ?? EpisodeID.ToString();
return $"{episode}.{Language ?? "und"}{index}{(IsForced ? ".forced" : string.Empty)}.{type}";
}
@@ -90,7 +90,7 @@ namespace Kyoo.Abstractions.Models
"Format: {episodeSlug}.{language}[-{index}][.forced].{type}[.{extension}]");
}
- EpisodeSlug = match.Groups["ep"].Value;
+ _episodeSlug = match.Groups["ep"].Value;
Language = match.Groups["lang"].Value;
if (Language == "und")
Language = null;
@@ -100,11 +100,6 @@ namespace Kyoo.Abstractions.Models
}
}
- ///
- /// The slug of the episode that contain this track. If this is not set, this track is ill-formed.
- ///
- [SerializeIgnore] public string EpisodeSlug { private get; set; }
-
///
/// The title of the stream.
///
@@ -153,7 +148,16 @@ namespace Kyoo.Abstractions.Models
///
/// The episode that uses this track.
///
- [LoadableRelation(nameof(EpisodeID))] public Episode Episode { get; set; }
+ [LoadableRelation(nameof(EpisodeID))] public Episode Episode
+ {
+ get => _episode;
+ set
+ {
+ _episode = value;
+ if (_episode != null)
+ _episodeSlug = _episode.Slug;
+ }
+ }
///
/// The index of this track on the episode.
@@ -184,6 +188,17 @@ namespace Kyoo.Abstractions.Models
}
}
+ ///
+ /// The slug of the episode that contain this track. If this is not set, this track is ill-formed.
+ ///
+ [SerializeIgnore] private string _episodeSlug;
+
+ ///
+ /// The episode that uses this track.
+ /// This is the baking field of .
+ ///
+ [SerializeIgnore] private Episode _episode;
+
// Converting mkv track language to c# system language tag.
private static string _GetLanguage(string mkvLanguage)
{
diff --git a/src/Kyoo.Abstractions/Models/Utils/Constants.cs b/src/Kyoo.Abstractions/Models/Utils/Constants.cs
new file mode 100644
index 00000000..7f857df1
--- /dev/null
+++ b/src/Kyoo.Abstractions/Models/Utils/Constants.cs
@@ -0,0 +1,55 @@
+// 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 Kyoo.Abstractions.Models.Attributes;
+
+namespace Kyoo.Abstractions.Models.Utils
+{
+ ///
+ /// A class containing constant numbers.
+ ///
+ public static class Constants
+ {
+ ///
+ /// A property to use on a Microsoft.AspNet.MVC.Route.Order property to mark it as an alternative route
+ /// that won't be included on the swagger.
+ ///
+ public const int AlternativeRoute = 1;
+
+ ///
+ /// A group name for . It should be used for main resources of kyoo.
+ ///
+ public const string ResourcesGroup = "0:Resources";
+
+ ///
+ /// A group name for .
+ /// It should be used for sub resources of kyoo that help define the main resources.
+ ///
+ public const string MetadataGroup = "1:Metadata";
+
+ ///
+ /// A group name for . It should be used for endpoints useful for playback.
+ ///
+ public const string WatchGroup = "2:Watch";
+
+ ///
+ /// A group name for . It should be used for endpoints used by admins.
+ ///
+ public const string AdminGroup = "3:Admin";
+ }
+}
diff --git a/src/Kyoo.Abstractions/Models/Utils/Identifier.cs b/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
new file mode 100644
index 00000000..7ded5348
--- /dev/null
+++ b/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
@@ -0,0 +1,215 @@
+// 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.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using JetBrains.Annotations;
+
+namespace Kyoo.Abstractions.Models.Utils
+{
+ ///
+ /// A class that represent a resource. It is made to be used as a parameter in a query and not used somewhere else
+ /// on the application.
+ /// This class allow routes to be used via ether IDs or Slugs, this is suitable for every .
+ ///
+ [TypeConverter(typeof(IdentifierConvertor))]
+ public class Identifier
+ {
+ ///
+ /// The ID of the resource or null if the slug is specified.
+ ///
+ private readonly int? _id;
+
+ ///
+ /// The slug of the resource or null if the id is specified.
+ ///
+ private readonly string _slug;
+
+ ///
+ /// Create a new for the given id.
+ ///
+ /// The id of the resource.
+ public Identifier(int id)
+ {
+ _id = id;
+ }
+
+ ///
+ /// Create a new for the given slug.
+ ///
+ /// The slug of the resource.
+ public Identifier([NotNull] string slug)
+ {
+ if (slug == null)
+ throw new ArgumentNullException(nameof(slug));
+ _slug = slug;
+ }
+
+ ///
+ /// Pattern match out of the identifier to a resource.
+ ///
+ /// The function to match the ID to a type .
+ /// The function to match the slug to a type .
+ /// The return type that will be converted to from an ID or a slug.
+ ///
+ /// The result of the or depending on the pattern.
+ ///
+ ///
+ /// Example usage:
+ ///
+ /// T ret = await identifier.Match(
+ /// id => _repository.GetOrDefault(id),
+ /// slug => _repository.GetOrDefault(slug)
+ /// );
+ ///
+ ///
+ public T Match(Func idFunc, Func slugFunc)
+ {
+ return _id.HasValue
+ ? idFunc(_id.Value)
+ : slugFunc(_slug);
+ }
+
+ ///
+ /// Match a custom type to an identifier. This can be used for wrapped resources (see example for more details).
+ ///
+ /// An expression to retrieve an ID from the type .
+ /// An expression to retrieve a slug from the type .
+ /// The type to match against this identifier.
+ /// An expression to match the type to this identifier.
+ ///
+ ///
+ /// identifier.Matcher<Season>(x => x.ShowID, x => x.Show.Slug)
+ ///
+ ///
+ public Expression> Matcher(Expression> idGetter,
+ Expression> slugGetter)
+ {
+ ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
+ BinaryExpression equal = Expression.Equal(_id.HasValue ? idGetter.Body : slugGetter.Body, self);
+ ICollection parameters = _id.HasValue ? idGetter.Parameters : slugGetter.Parameters;
+ return Expression.Lambda>(equal, parameters);
+ }
+
+ ///
+ /// A matcher overload for nullable IDs. See
+ ///
+ /// for more details.
+ ///
+ /// An expression to retrieve an ID from the type .
+ /// An expression to retrieve a slug from the type .
+ /// The type to match against this identifier.
+ /// An expression to match the type to this identifier.
+ public Expression> Matcher(Expression> idGetter,
+ Expression> slugGetter)
+ {
+ ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
+ BinaryExpression equal = Expression.Equal(_id.HasValue ? idGetter.Body : slugGetter.Body, self);
+ ICollection parameters = _id.HasValue ? idGetter.Parameters : slugGetter.Parameters;
+ return Expression.Lambda>(equal, parameters);
+ }
+
+ ///
+ /// Return true if this match a resource.
+ ///
+ /// The resource to match
+ ///
+ /// true if the match this identifier, false otherwise.
+ ///
+ public bool IsSame(IResource resource)
+ {
+ return Match(
+ id => resource.ID == id,
+ slug => resource.Slug == slug
+ );
+ }
+
+ ///
+ /// Return an expression that return true if this match a given resource.
+ ///
+ /// The type of resource to match against.
+ ///
+ /// true if the given resource match this identifier, false otherwise.
+ ///
+ public Expression> IsSame()
+ where T : IResource
+ {
+ return _id.HasValue
+ ? x => x.ID == _id.Value
+ : x => x.Slug == _slug;
+ }
+
+ ///
+ /// Return an expression that return true if this is containing in a collection.
+ ///
+ /// An expression to retrieve the list to check.
+ /// The type that contain the list to check.
+ /// The type of resource to check this identifier against.
+ /// An expression to check if this is contained.
+ public Expression> IsContainedIn(Expression>> listGetter)
+ where T2 : IResource
+ {
+ MethodInfo method = typeof(Enumerable)
+ .GetMethods()
+ .Where(x => x.Name == nameof(Enumerable.Any))
+ .FirstOrDefault(x => x.GetParameters().Length == 2)!
+ .MakeGenericMethod(typeof(T2));
+ MethodCallExpression call = Expression.Call(null, method!, listGetter.Body, IsSame());
+ return Expression.Lambda>(call, listGetter.Parameters);
+ }
+
+ ///
+ public override string ToString()
+ {
+ return _id.HasValue
+ ? _id.Value.ToString()
+ : _slug;
+ }
+
+ ///
+ /// A custom used to convert int or strings to an .
+ ///
+ public class IdentifierConvertor : TypeConverter
+ {
+ ///
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(int) || sourceType == typeof(string))
+ return true;
+ return base.CanConvertFrom(context, sourceType);
+ }
+
+ ///
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value is int id)
+ return new Identifier(id);
+ if (value is not string slug)
+ return base.ConvertFrom(context, culture, value);
+ return int.TryParse(slug, out id)
+ ? new Identifier(id)
+ : new Identifier(slug);
+ }
+ }
+ }
+}
diff --git a/src/Kyoo.Abstractions/Models/Utils/Pagination.cs b/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
index 652991a1..e52bbf63 100644
--- a/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
+++ b/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
@@ -31,14 +31,14 @@ namespace Kyoo.Abstractions.Controllers
///
/// Where to start? Using the given sort.
///
- public int AfterID { get; }
+ public int? AfterID { get; }
///
/// Create a new instance.
///
/// Set the value
/// Set the value. If not specified, it will start from the start
- public Pagination(int count, int afterID = 0)
+ public Pagination(int count, int? afterID = null)
{
Count = count;
AfterID = afterID;
diff --git a/src/Kyoo.Abstractions/Models/Utils/RequestError.cs b/src/Kyoo.Abstractions/Models/Utils/RequestError.cs
new file mode 100644
index 00000000..fa40fc64
--- /dev/null
+++ b/src/Kyoo.Abstractions/Models/Utils/RequestError.cs
@@ -0,0 +1,58 @@
+// 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.Linq;
+using JetBrains.Annotations;
+
+namespace Kyoo.Abstractions.Models.Utils
+{
+ ///
+ /// The list of errors that where made in the request.
+ ///
+ public class RequestError
+ {
+ ///
+ /// The list of errors that where made in the request.
+ ///
+ /// ["InvalidFilter: no field 'startYear' on a collection"]
+ [NotNull] public string[] Errors { get; set; }
+
+ ///
+ /// Create a new with one error.
+ ///
+ /// The error to specify in the response.
+ public RequestError([NotNull] string error)
+ {
+ if (error == null)
+ throw new ArgumentNullException(nameof(error));
+ Errors = new[] { error };
+ }
+
+ ///
+ /// Create a new with multiple errors.
+ ///
+ /// The errors to specify in the response.
+ public RequestError([NotNull] string[] errors)
+ {
+ if (errors == null || !errors.Any())
+ throw new ArgumentException("Errors must be non null and not empty", nameof(errors));
+ Errors = errors;
+ }
+ }
+}
diff --git a/src/Kyoo.Abstractions/Models/WatchItem.cs b/src/Kyoo.Abstractions/Models/WatchItem.cs
index 8c4daab9..bedd5df5 100644
--- a/src/Kyoo.Abstractions/Models/WatchItem.cs
+++ b/src/Kyoo.Abstractions/Models/WatchItem.cs
@@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -32,7 +33,7 @@ namespace Kyoo.Abstractions.Models
/// Information about tracks and display information that could be used by the player.
/// This contains mostly data from an with another form.
///
- public class WatchItem
+ public class WatchItem : CustomTypeDescriptor, IThumbnails
{
///
/// The ID of the episode associated with this item.
@@ -101,26 +102,8 @@ namespace Kyoo.Abstractions.Models
///
public bool IsMovie { get; set; }
- ///
- /// The path of this item's poster.
- /// By default, the http path for the poster is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/show/{ShowSlug}/poster")] public string Poster { get; set; }
-
- ///
- /// The path of this item's logo.
- /// By default, the http path for the logo is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/show/{ShowSlug}/logo")] public string Logo { get; set; }
-
- ///
- /// The path of this item's backdrop.
- /// By default, the http path for the backdrop is returned from the public API.
- /// This can be disabled using the internal query flag.
- ///
- [SerializeAs("{HOST}/api/show/{ShowSlug}/backdrop")] public string Backdrop { get; set; }
+ ///
+ public Dictionary Images { get; set; }
///
/// The container of the video file of this episode.
@@ -158,36 +141,50 @@ namespace Kyoo.Abstractions.Models
/// A new WatchItem representing the given episode.
public static async Task FromEpisode(Episode ep, ILibraryManager library)
{
- Episode previous = null;
- Episode next = null;
-
await library.Load(ep, x => x.Show);
await library.Load(ep, x => x.Tracks);
- if (!ep.Show.IsMovie && ep.SeasonNumber != null && ep.EpisodeNumber != null)
+ Episode previous = null;
+ Episode next = null;
+ if (!ep.Show.IsMovie)
{
- if (ep.EpisodeNumber > 1)
- previous = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value, ep.EpisodeNumber.Value - 1);
- else if (ep.SeasonNumber > 1)
+ if (ep.AbsoluteNumber != null)
{
- previous = (await library.GetAll(x => x.ShowID == ep.ShowID
- && x.SeasonNumber == ep.SeasonNumber.Value - 1,
- limit: 1,
- sort: new Sort(x => x.EpisodeNumber, true))
- ).FirstOrDefault();
+ previous = await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID && x.AbsoluteNumber < ep.AbsoluteNumber,
+ new Sort(x => x.AbsoluteNumber, true)
+ );
+ next = await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID && x.AbsoluteNumber > ep.AbsoluteNumber,
+ new Sort(x => x.AbsoluteNumber)
+ );
}
+ else if (ep.SeasonNumber != null && ep.EpisodeNumber != null)
+ {
+ previous = await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID
+ && x.SeasonNumber == ep.SeasonNumber
+ && x.EpisodeNumber < ep.EpisodeNumber,
+ new Sort(x => x.EpisodeNumber, true)
+ );
+ previous ??= await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID
+ && x.SeasonNumber == ep.SeasonNumber - 1,
+ new Sort(x => x.EpisodeNumber, true)
+ );
- if (ep.EpisodeNumber >= await library.GetCount(x => x.SeasonID == ep.SeasonID))
- next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value + 1, 1);
- else
- next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value, ep.EpisodeNumber.Value + 1);
- }
- else if (!ep.Show.IsMovie && ep.AbsoluteNumber != null)
- {
- previous = await library.GetOrDefault(x => x.ShowID == ep.ShowID
- && x.AbsoluteNumber == ep.EpisodeNumber + 1);
- next = await library.GetOrDefault(x => x.ShowID == ep.ShowID
- && x.AbsoluteNumber == ep.AbsoluteNumber + 1);
+ next = await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID
+ && x.SeasonNumber == ep.SeasonNumber
+ && x.EpisodeNumber > ep.EpisodeNumber,
+ new Sort(x => x.EpisodeNumber)
+ );
+ next ??= await library.GetOrDefault(
+ x => x.ShowID == ep.ShowID
+ && x.SeasonNumber == ep.SeasonNumber + 1,
+ new Sort(x => x.EpisodeNumber)
+ );
+ }
}
return new WatchItem
@@ -202,6 +199,7 @@ namespace Kyoo.Abstractions.Models
Title = ep.Title,
ReleaseDate = ep.ReleaseDate,
Path = ep.Path,
+ Images = ep.Show.Images,
Container = PathIO.GetExtension(ep.Path)![1..],
Video = ep.Tracks.FirstOrDefault(x => x.Type == StreamType.Video),
Audios = ep.Tracks.Where(x => x.Type == StreamType.Audio).ToArray(),
@@ -239,5 +237,17 @@ namespace Kyoo.Abstractions.Models
return Array.Empty();
}
}
+
+ ///
+ public override string GetClassName()
+ {
+ return nameof(Show);
+ }
+
+ ///
+ public override string GetComponentName()
+ {
+ return ShowSlug;
+ }
}
}
diff --git a/src/Kyoo.Abstractions/Module.cs b/src/Kyoo.Abstractions/Module.cs
index 102b9e2e..e0f8c53f 100644
--- a/src/Kyoo.Abstractions/Module.cs
+++ b/src/Kyoo.Abstractions/Module.cs
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
+using System;
using Autofac;
using Autofac.Builder;
using Kyoo.Abstractions.Controllers;
@@ -96,9 +97,10 @@ namespace Kyoo.Abstractions
///
/// The configuration instance
/// The public URl of kyoo (without a slash at the end)
- public static string GetPublicUrl(this IConfiguration configuration)
+ public static Uri GetPublicUrl(this IConfiguration configuration)
{
- return configuration["basics:publicUrl"]?.TrimEnd('/') ?? "http://localhost:5000";
+ string uri = configuration["basics:publicUrl"]?.TrimEnd('/') ?? "http://localhost:5000";
+ return new Uri(uri);
}
}
}
diff --git a/src/Kyoo.Abstractions/Utility/Utility.cs b/src/Kyoo.Abstractions/Utility/Utility.cs
index 5c0dcc80..04a1f948 100644
--- a/src/Kyoo.Abstractions/Utility/Utility.cs
+++ b/src/Kyoo.Abstractions/Utility/Utility.cs
@@ -425,6 +425,11 @@ namespace Kyoo.Utils
return (T)method.MakeGenericMethod(types).Invoke(instance, args.ToArray());
}
+ ///
+ /// Convert a dictionary to a query string.
+ ///
+ /// The list of query parameters.
+ /// A valid query string with all items in the dictionary.
public static string ToQueryString(this Dictionary query)
{
if (!query.Any())
@@ -432,6 +437,11 @@ namespace Kyoo.Utils
return "?" + string.Join('&', query.Select(x => $"{x.Key}={x.Value}"));
}
+ ///
+ /// Rethrow the exception without modifying the stack trace.
+ /// This is similar to the rethrow; code but is useful when the exception is not in a catch block.
+ ///
+ /// The exception to rethrow.
[System.Diagnostics.CodeAnalysis.DoesNotReturn]
public static void ReThrow([NotNull] this Exception ex)
{
diff --git a/src/Kyoo.Authentication/AuthenticationModule.cs b/src/Kyoo.Authentication/AuthenticationModule.cs
index 82a224fa..d5e73eb9 100644
--- a/src/Kyoo.Authentication/AuthenticationModule.cs
+++ b/src/Kyoo.Authentication/AuthenticationModule.cs
@@ -104,7 +104,7 @@ namespace Kyoo.Authentication
DefaultCorsPolicyService cors = new(_logger)
{
- AllowedOrigins = { new Uri(_configuration.GetPublicUrl()).GetLeftPart(UriPartial.Authority) }
+ AllowedOrigins = { _configuration.GetPublicUrl().GetLeftPart(UriPartial.Authority) }
};
builder.RegisterInstance(cors).As().SingleInstance();
}
@@ -112,7 +112,7 @@ namespace Kyoo.Authentication
///
public void Configure(IServiceCollection services)
{
- string publicUrl = _configuration.GetPublicUrl();
+ Uri publicUrl = _configuration.GetPublicUrl();
if (_environment.IsDevelopment())
IdentityModelEventSource.ShowPII = true;
@@ -136,7 +136,7 @@ namespace Kyoo.Authentication
services.AddIdentityServer(options =>
{
- options.IssuerUri = publicUrl;
+ options.IssuerUri = publicUrl.ToString();
options.UserInteraction.LoginUrl = $"{publicUrl}/login";
options.UserInteraction.ErrorUrl = $"{publicUrl}/error";
options.UserInteraction.LogoutUrl = $"{publicUrl}/logout";
@@ -151,7 +151,7 @@ namespace Kyoo.Authentication
services.AddAuthentication()
.AddJwtBearer(options =>
{
- options.Authority = publicUrl;
+ options.Authority = publicUrl.ToString();
options.Audience = "kyoo";
options.RequireHttpsMetadata = false;
});
@@ -189,7 +189,7 @@ namespace Kyoo.Authentication
{
app.Use((ctx, next) =>
{
- ctx.SetIdentityServerOrigin(_configuration.GetPublicUrl());
+ ctx.SetIdentityServerOrigin(_configuration.GetPublicUrl().ToString());
return next();
});
app.UseIdentityServer();
diff --git a/src/Kyoo.Authentication/Controllers/PasswordUtils.cs b/src/Kyoo.Authentication/Controllers/PasswordUtils.cs
index fb2982ba..5c071a4e 100644
--- a/src/Kyoo.Authentication/Controllers/PasswordUtils.cs
+++ b/src/Kyoo.Authentication/Controllers/PasswordUtils.cs
@@ -23,6 +23,9 @@ using IdentityModel;
namespace Kyoo.Authentication
{
+ ///
+ /// Some functions to handle password management.
+ ///
public static class PasswordUtils
{
///
diff --git a/src/Kyoo.Authentication/Controllers/PermissionValidator.cs b/src/Kyoo.Authentication/Controllers/PermissionValidator.cs
index 2f4a84f4..490c7649 100644
--- a/src/Kyoo.Authentication/Controllers/PermissionValidator.cs
+++ b/src/Kyoo.Authentication/Controllers/PermissionValidator.cs
@@ -61,7 +61,7 @@ namespace Kyoo.Authentication
///
public IFilterMetadata Create(PartialPermissionAttribute attribute)
{
- return new PermissionValidatorFilter((object)attribute.Type ?? attribute.Kind, _options);
+ return new PermissionValidatorFilter((object)attribute.Type ?? attribute.Kind, attribute.Group, _options);
}
///
@@ -109,15 +109,24 @@ namespace Kyoo.Authentication
/// Create a new permission validator with the given options.
///
/// The partial permission to validate.
+ /// The group of the permission.
/// The option containing default values.
- public PermissionValidatorFilter(object partialInfo, IOptionsMonitor options)
+ public PermissionValidatorFilter(object partialInfo, Group? group, IOptionsMonitor options)
{
- if (partialInfo is Kind kind)
- _kind = kind;
- else if (partialInfo is string perm)
- _permission = perm;
- else
- throw new ArgumentException($"{nameof(partialInfo)} can only be a permission string or a kind.");
+ switch (partialInfo)
+ {
+ case Kind kind:
+ _kind = kind;
+ break;
+ case string perm:
+ _permission = perm;
+ break;
+ default:
+ throw new ArgumentException($"{nameof(partialInfo)} can only be a permission string or a kind.");
+ }
+
+ if (group != null)
+ _group = group.Value;
_options = options;
}
diff --git a/src/Kyoo.Authentication/Models/DTO/OtacResponse.cs b/src/Kyoo.Authentication/Models/DTO/OtacResponse.cs
new file mode 100644
index 00000000..13ff8aac
--- /dev/null
+++ b/src/Kyoo.Authentication/Models/DTO/OtacResponse.cs
@@ -0,0 +1,41 @@
+// 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 .
+
+namespace Kyoo.Authentication.Models.DTO
+{
+ ///
+ /// A one time access token
+ ///
+ public class OtacResponse
+ {
+ ///
+ /// The One Time Access Token that allow one to connect to an account without typing a password or without
+ /// any kind of verification. This is valid only one time and only for a short period of time.
+ ///
+ public string OTAC { get; set; }
+
+ ///
+ /// Create a new .
+ ///
+ /// The one time access token.
+ public OtacResponse(string otac)
+ {
+ OTAC = otac;
+ }
+ }
+}
diff --git a/src/Kyoo.Authentication/Views/AccountApi.cs b/src/Kyoo.Authentication/Views/AccountApi.cs
index af569655..a2cbf2f2 100644
--- a/src/Kyoo.Authentication/Views/AccountApi.cs
+++ b/src/Kyoo.Authentication/Views/AccountApi.cs
@@ -28,7 +28,9 @@ using IdentityServer4.Models;
using IdentityServer4.Services;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
+using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
+using Kyoo.Abstractions.Models.Utils;
using Kyoo.Authentication.Models;
using Kyoo.Authentication.Models.DTO;
using Microsoft.AspNetCore.Authentication;
@@ -36,15 +38,19 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
+using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Authentication.Views
{
///
- /// The class responsible for login, logout, permissions and claims of a user.
+ /// The endpoint responsible for login, logout, permissions and claims of a user.
+ /// Documentation of this endpoint is a work in progress.
///
- [Route("api/account")]
+ /// TODO document this well.
[Route("api/accounts")]
+ [Route("api/account", Order = AlternativeRoute)]
[ApiController]
+ [ApiDefinition("Account")]
public class AccountApi : Controller, IProfileService
{
///
@@ -78,12 +84,17 @@ namespace Kyoo.Authentication.Views
}
///
- /// Register a new user and return a OTAC to connect to it.
+ /// Register
///
+ ///
+ /// Register a new user and return a OTAC to connect to it.
+ ///
/// The DTO register request
/// A OTAC to connect to this new account
[HttpPost("register")]
- public async Task Register([FromBody] RegisterRequest request)
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status409Conflict, Type = typeof(RequestError))]
+ public async Task> Register([FromBody] RegisterRequest request)
{
User user = request.ToUser();
user.Permissions = _options.Value.Permissions.NewUser;
@@ -96,10 +107,10 @@ namespace Kyoo.Authentication.Views
}
catch (DuplicatedItemException)
{
- return Conflict(new { Errors = new { Duplicate = new[] { "A user with this name already exists" } } });
+ return Conflict(new RequestError("A user with this name already exists"));
}
- return Ok(new { Otac = user.ExtraData["otac"] });
+ return Ok(new OtacResponse(user.ExtraData["otac"]));
}
///
@@ -119,8 +130,11 @@ namespace Kyoo.Authentication.Views
}
///
- /// Login the user.
+ /// Login
///
+ ///
+ /// Login the current session.
+ ///
/// The DTO login request
/// TODO
[HttpPost("login")]
@@ -177,6 +191,7 @@ namespace Kyoo.Authentication.Views
}
///
+ [ApiExplorerSettings(IgnoreApi = true)]
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
User user = await _users.GetOrDefault(int.Parse(context.Subject.GetSubjectId()));
@@ -187,6 +202,7 @@ namespace Kyoo.Authentication.Views
}
///
+ [ApiExplorerSettings(IgnoreApi = true)]
public async Task IsActiveAsync(IsActiveContext context)
{
User user = await _users.GetOrDefault(int.Parse(context.Subject.GetSubjectId()));
diff --git a/src/Kyoo.Core/Application.cs b/src/Kyoo.Core/Application.cs
index 7b0f4961..f1ee2fda 100644
--- a/src/Kyoo.Core/Application.cs
+++ b/src/Kyoo.Core/Application.cs
@@ -283,7 +283,7 @@ namespace Kyoo.Core
builder.ReadFrom.Services(services);
const string template =
- "[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 15} "
+ "[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 25} "
+ "({@i:D10})] {@m}{#if not EndsWith(@m, '\n')}\n{#end}{@x}";
if (SystemdHelpers.IsSystemdService())
diff --git a/src/Kyoo.Core/Controllers/ConfigurationManager.cs b/src/Kyoo.Core/Controllers/ConfigurationManager.cs
index 760e3a95..10e0843b 100644
--- a/src/Kyoo.Core/Controllers/ConfigurationManager.cs
+++ b/src/Kyoo.Core/Controllers/ConfigurationManager.cs
@@ -32,6 +32,11 @@ using Newtonsoft.Json.Linq;
namespace Kyoo.Core.Controllers
{
+ ///
+ /// A class to ease configuration management. This work WITH Microsoft's package, you can still use IOptions patterns
+ /// to access your options, this manager ease dynamic work and editing.
+ /// It works with .
+ ///
public class ConfigurationManager : IConfigurationManager
{
///
diff --git a/src/Kyoo.Core/Controllers/FileSystems/FileSystemComposite.cs b/src/Kyoo.Core/Controllers/FileSystems/FileSystemComposite.cs
index 343b4277..8973d26b 100644
--- a/src/Kyoo.Core/Controllers/FileSystems/FileSystemComposite.cs
+++ b/src/Kyoo.Core/Controllers/FileSystems/FileSystemComposite.cs
@@ -214,5 +214,19 @@ namespace Kyoo.Core.Controllers
};
return await CreateDirectory(path);
}
+
+ ///
+ public Task> ExtractInfos(Episode episode, bool reExtract)
+ {
+ IFileSystem fs = _GetFileSystemForPath(episode.Path, out string _);
+ return fs.ExtractInfos(episode, reExtract);
+ }
+
+ ///
+ public IActionResult Transmux(Episode episode)
+ {
+ IFileSystem fs = _GetFileSystemForPath(episode.Path, out string _);
+ return fs.Transmux(episode);
+ }
}
}
diff --git a/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs b/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs
index 662d1825..e004b796 100644
--- a/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs
+++ b/src/Kyoo.Core/Controllers/FileSystems/HttpFileSystem.cs
@@ -110,6 +110,18 @@ namespace Kyoo.Core.Controllers
throw new NotSupportedException("Extras can not be stored inside an http filesystem.");
}
+ ///
+ public Task> ExtractInfos(Episode episode, bool reExtract)
+ {
+ throw new NotSupportedException("Extracting infos is not supported on an http filesystem.");
+ }
+
+ ///
+ public IActionResult Transmux(Episode episode)
+ {
+ throw new NotSupportedException("Transmuxing is not supported on an http filesystem.");
+ }
+
///
/// An to proxy an http request.
///
diff --git a/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs b/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs
index 67bcc97c..44fe5154 100644
--- a/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs
+++ b/src/Kyoo.Core/Controllers/FileSystems/LocalFileSystem.cs
@@ -41,6 +41,11 @@ namespace Kyoo.Core.Controllers
///
private readonly IContentTypeProvider _provider;
+ ///
+ /// The transcoder of local files.
+ ///
+ private readonly ITranscoder _transcoder;
+
///
/// Options to check if the metadata should be kept in the show directory or in a kyoo's directory.
///
@@ -51,10 +56,14 @@ namespace Kyoo.Core.Controllers
///
/// The options to use.
/// An extension provider to get content types from files extensions.
- public LocalFileSystem(IOptionsMonitor options, IContentTypeProvider provider)
+ /// The transcoder of local files.
+ public LocalFileSystem(IOptionsMonitor options,
+ IContentTypeProvider provider,
+ ITranscoder transcoder)
{
_options = options;
_provider = provider;
+ _transcoder = transcoder;
}
///
@@ -155,5 +164,17 @@ namespace Kyoo.Core.Controllers
_ => null
});
}
+
+ ///
+ public Task> ExtractInfos(Episode episode, bool reExtract)
+ {
+ return _transcoder.ExtractInfos(episode, reExtract);
+ }
+
+ ///
+ public IActionResult Transmux(Episode episode)
+ {
+ return _transcoder.Transmux(episode);
+ }
}
}
diff --git a/src/Kyoo.Abstractions/Controllers/ITranscoder.cs b/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
similarity index 60%
rename from src/Kyoo.Abstractions/Controllers/ITranscoder.cs
rename to src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
index 20213526..cda79146 100644
--- a/src/Kyoo.Abstractions/Controllers/ITranscoder.cs
+++ b/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
@@ -16,17 +16,25 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
-using System.Threading.Tasks;
-using Kyoo.Abstractions.Models;
+using Kyoo.Abstractions.Models.Utils;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
-namespace Kyoo.Abstractions.Controllers
+namespace Kyoo.Core.Controllers
{
- public interface ITranscoder
+ ///
+ /// The route constraint that goes with the .
+ ///
+ public class IdentifierRouteConstraint : IRouteConstraint
{
- Task