Merge pull request #39 from AnonymusRaccoon/coding-style

Enforcing coding style
This commit is contained in:
Zoe Roux 2021-09-13 21:35:01 +02:00 committed by GitHub
commit 66d6b27e38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
265 changed files with 9097 additions and 5137 deletions

91
.editorconfig Normal file
View File

@ -0,0 +1,91 @@
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = tab
indent_size = tab
smart_tab = true
[{*.yaml,*.yml}]
indent_style = space
indent_size = 2
[*.cs]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
csharp_using_directive_placement = outside_namespace:warning
# Avoid "this." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Suggest more modern language features when available
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
# Disable strange throw.
csharp_style_throw_expression = false:suggestion
# Forbid "var" everywhere
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = false:warning
csharp_style_var_elsewhere = false:warning
# Prefer method-like constructs to have a block body
csharp_style_expression_bodied_methods = false:none
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_operators = false:none
# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_before_members_in_anonymous_types = true
# Indentation settings
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
# Modifiers
dotnet_style_readonly_field = true:suggestion
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# Naming style
dotnet_naming_symbols.privates.applicable_kinds = property,method,event,delegate
dotnet_naming_symbols.privates.applicable_accessibilities = private
dotnet_naming_style.underscore_pascal.capitalization = pascal_case
dotnet_naming_style.underscore_pascal.required_prefix = _
dotnet_naming_rule.privates_with_underscore.symbols = privates
dotnet_naming_rule.privates_with_underscore.style = underscore_pascal
dotnet_naming_rule.privates_with_underscore.severity = warning
dotnet_diagnostic.IDE1006.severity = warning
# ReSharper properties
resharper_align_multiline_binary_expressions_chain = false
resharper_csharp_empty_block_style = together_same_line
resharper_indent_nested_foreach_stmt = true
resharper_indent_nested_for_stmt = true
resharper_indent_nested_while_stmt = true
resharper_keep_existing_embedded_arrangement = false
resharper_place_accessorholder_attribute_on_same_line = true
resharper_place_simple_embedded_statement_on_same_line = false
resharper_wrap_before_arrow_with_expressions = true
resharper_xmldoc_attribute_indent = align_by_first_attribute
resharper_xmldoc_indent_child_elements = RemoveIndent
resharper_xmldoc_indent_text = RemoveIndent

View File

@ -45,8 +45,8 @@ jobs:
shell: bash
run: |
echo "PROJECT=$([ "${{runner.os}}" == "Windows" ] \
&& echo " -p:IncludeConsole=true Kyoo.Host.WindowsTrait" \
|| echo Kyoo.Host.Console)" >> $GITHUB_ENV
&& echo " -p:IncludeConsole=true -p:CheckCodingStyle=false src/Kyoo.Host.WindowsTrait" \
|| echo " -p:CheckCodingStyle=false src/Kyoo.Host.Console")" >> $GITHUB_ENV
- name: Build the app
env:
INCLUDE: ${{env.INCLUDE}};C:\Program Files\FFmpeg\include

15
.github/workflows/coding-style.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: CodingStyle
on: [pull_request, workflow_dispatch]
jobs:
build:
name: "Coding style check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Build the app
run: dotnet build -p:CheckCodingStyle=true -p:TreatWarningsAsErrors=true '-p:SkipTranscoder=true;SkipWebApp=true'

View File

@ -24,7 +24,7 @@ jobs:
- name: Build
run: |
dotnet build --no-restore '-p:SkipWebApp=true;SkipTranscoder=true' -p:CopyLocalLockFileAssemblies=true
cp ./Kyoo.Abstractions/bin/Debug/net5.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./tests/Kyoo.Tests/bin/Debug/net5.0/
cp ./src/Kyoo.Abstractions/bin/Debug/net5.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./tests/Kyoo.Tests/bin/Debug/net5.0/
- name: Test
run: dotnet test --no-build '-p:CollectCoverage=true;CoverletOutputFormat=opencover'
env:

4
.gitmodules vendored
View File

@ -1,8 +1,8 @@
[submodule "transcoder"]
path = Kyoo.Transcoder
path = src/Kyoo.Transcoder
url = ../Kyoo.Transcoder.git
branch = master
[submodule "WebApp"]
path = Kyoo.WebApp/Front
path = src/Kyoo.WebApp/Front
url = ../Kyoo.WebApp.git
branch = master

4
AUTHORS.md Normal file
View File

@ -0,0 +1,4 @@
# Authors
Alphabetical order by first name.
* Zoe Roux ([@AnonymusRaccoon](http://github.com/AnonymusRaccoon))

View File

@ -1,12 +1,12 @@
FROM gcc:latest as transcoder
RUN apt-get update && apt-get install -y cmake make libavutil-dev libavcodec-dev libavformat-dev
WORKDIR /transcoder
COPY Kyoo.Transcoder .
COPY src/Kyoo.Transcoder .
RUN cmake . && make -j
FROM node:alpine as webapp
WORKDIR /webapp
COPY Kyoo.WebApp .
COPY src/Kyoo.WebApp .
WORKDIR /webapp/Front
RUN npm install
RUN npm run build -- --prod

View File

@ -1,31 +0,0 @@
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// An interface that allow one to interact with the host and shutdown or restart the app.
/// </summary>
public interface IApplication
{
/// <summary>
/// Shutdown the process and stop gracefully.
/// </summary>
void Shutdown();
/// <summary>
/// Restart Kyoo from scratch, reload plugins, configurations and restart the web server.
/// </summary>
void Restart();
/// <summary>
/// Get the data directory
/// </summary>
/// <returns>Retrieve the data directory where runtime data should be stored</returns>
string GetDataDirectory();
/// <summary>
/// Retrieve the path of the json configuration file
/// (relative to the data directory, see <see cref="GetDataDirectory"/>).
/// </summary>
/// <returns>The configuration file name.</returns>
string GetConfigFile();
}
}

View File

@ -1,12 +0,0 @@
using Kyoo.Abstractions.Models;
using System.Threading.Tasks;
namespace Kyoo.Abstractions.Controllers
{
public interface ITranscoder
{
Task<Track[]> ExtractInfos(Episode episode, bool reextract);
Task<string> Transmux(Episode episode);
Task<string> Transcode(Episode episode);
}
}

View File

@ -1,221 +0,0 @@
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// A list of constant priorities used for <see cref="IStartupAction"/>'s <see cref="IStartupAction.Priority"/>.
/// It also contains helper methods for creating new <see cref="StartupAction"/>.
/// </summary>
public static class SA
{
public const int Before = 5000;
public const int Routing = 4000;
public const int StaticFiles = 3000;
public const int Authentication = 2000;
public const int Authorization = 1000;
public const int Endpoint = 0;
public const int After = -1000;
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction New(Action action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T> New<T>(Action<T> action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
=> new(action, priority);
}
/// <summary>
/// An action executed on kyoo's startup to initialize the asp-net container.
/// </summary>
/// <remarks>
/// This is the base interface, see <see cref="StartupAction"/> for a simpler use of this.
/// </remarks>
public interface IStartupAction
{
/// <summary>
/// The priority of this action. The actions will be executed on descending priority order.
/// If two actions have the same priority, their order is undefined.
/// </summary>
int Priority { get; }
/// <summary>
/// Run this action to configure the container, a service provider containing all services can be used.
/// </summary>
/// <param name="provider">The service provider containing all services can be used.</param>
void Run(IServiceProvider provider);
}
/// <summary>
/// A <see cref="IStartupAction"/> with no dependencies.
/// </summary>
public class StartupAction : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke();
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with one dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
public class StartupAction<T> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(provider.GetRequiredService<T>());
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with two dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
/// <typeparam name="T2">The second dependency to use.</typeparam>
public class StartupAction<T, T2> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T, T2> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T, T2}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T, T2> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(
provider.GetRequiredService<T>(),
provider.GetRequiredService<T2>()
);
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with three dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
/// <typeparam name="T2">The second dependency to use.</typeparam>
/// <typeparam name="T3">The third dependency to use.</typeparam>
public class StartupAction<T, T2, T3> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T, T2, T3> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T, T2, T3> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(
provider.GetRequiredService<T>(),
provider.GetRequiredService<T2>(),
provider.GetRequiredService<T3>()
);
}
}
}

View File

@ -1,17 +0,0 @@
namespace Kyoo.Abstractions.Models
{
/// <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; }
}
}

View File

@ -1,10 +0,0 @@
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ComputedAttribute : NotMergeableAttribute { }
}

View File

@ -1,22 +0,0 @@
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// Specify that a property can't be merged.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NotMergeableAttribute : Attribute { }
/// <summary>
/// An interface with a method called when this object is merged.
/// </summary>
public interface IOnMerge
{
/// <summary>
/// This function is called after the object has been merged.
/// </summary>
/// <param name="merged">The object that has been merged with this.</param>
void OnMerge(object merged);
}
}

View File

@ -1,172 +0,0 @@
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Abstractions.Models.Permissions
{
/// <summary>
/// The kind of permission needed.
/// </summary>
public enum Kind
{
Read,
Write,
Create,
Delete
}
/// <summary>
/// The group of the permission.
/// </summary>
public enum Group
{
Overall,
Admin
}
/// <summary>
/// Specify permissions needed for the API.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : Attribute, IFilterFactory
{
/// <summary>
/// The needed permission as string.
/// </summary>
public string Type { get; }
/// <summary>
/// The needed permission kind.
/// </summary>
public Kind Kind { get; }
/// <summary>
/// The group of this permission
/// </summary>
public Group Group { get; }
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <param name="type">
/// The type of the action
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
/// </param>
/// <param name="permission">The kind of permission needed</param>
/// <param name="group">
/// The group of this permission (allow grouped permission like overall.read
/// for all read permissions of this group)
/// </param>
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;
}
/// <inheritdoc />
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
}
/// <inheritdoc />
public bool IsReusable => true;
/// <summary>
/// Return this permission attribute as a string
/// </summary>
/// <returns>The string representation.</returns>
public string AsPermissionString()
{
return Type;
}
}
/// <summary>
/// Specify one part of a permissions needed for the API (the kind or the type).
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PartialPermissionAttribute : Attribute, IFilterFactory
{
/// <summary>
/// The needed permission type.
/// </summary>
public string Type { get; }
/// <summary>
/// The needed permission kind.
/// </summary>
public Kind Kind { get; }
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <remarks>
/// With this attribute, you can only specify a type or a kind.
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
/// lead to unspecified behaviors.
/// </remarks>
/// <param name="type">
/// The type of the action
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
/// </param>
public PartialPermissionAttribute(string type)
{
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
type = type[..^3];
Type = type.ToLower();
}
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <remarks>
/// With this attribute, you can only specify a type or a kind.
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
/// lead to unspecified behaviors.
/// </remarks>
/// <param name="permission">The kind of permission needed</param>
public PartialPermissionAttribute(Kind permission)
{
Kind = permission;
}
/// <inheritdoc />
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
}
/// <inheritdoc />
public bool IsReusable => true;
}
/// <summary>
/// A service to validate permissions
/// </summary>
public interface IPermissionValidator
{
/// <summary>
/// Create an IAuthorizationFilter that will be used to validate permissions.
/// This can registered with any lifetime.
/// </summary>
/// <param name="attribute">The permission attribute to validate</param>
/// <returns>An authorization filter used to validate the permission</returns>
IFilterMetadata Create(PermissionAttribute attribute);
/// <summary>
/// Create an IAuthorizationFilter that will be used to validate permissions.
/// This can registered with any lifetime.
/// </summary>
/// <param name="attribute">
/// A partial attribute to validate. See <see cref="PartialPermissionAttribute"/>.
/// </param>
/// <returns>An authorization filter used to validate the permission</returns>
IFilterMetadata Create(PartialPermissionAttribute attribute);
}
}

View File

@ -1,28 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
namespace Kyoo.Authentication.Models.DTO
{
/// <summary>
/// A model only used on account update requests.
/// </summary>
public class AccountUpdateRequest
{
/// <summary>
/// The new email address of the user
/// </summary>
[EmailAddress(ErrorMessage = "The email is invalid.")]
public string Email { get; set; }
/// <summary>
/// The new username of the user.
/// </summary>
[MinLength(4, ErrorMessage = "The username must have at least 4 characters")]
public string Username { get; set; }
/// <summary>
/// The picture icon.
/// </summary>
public IFormFile Picture { get; set; }
}
}

View File

@ -1,28 +0,0 @@
namespace Kyoo.Authentication.Models.DTO
{
/// <summary>
/// A model only used on login requests.
/// </summary>
public class LoginRequest
{
/// <summary>
/// The user's username.
/// </summary>
public string Username { get; set; }
/// <summary>
/// The user's password.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Should the user stay logged in? If true a cookie will be put.
/// </summary>
public bool StayLoggedIn { get; set; }
/// <summary>
/// The return url of the login flow.
/// </summary>
public string ReturnURL { get; set; }
}
}

View File

@ -1,18 +0,0 @@
namespace Kyoo.Authentication.Models.DTO
{
/// <summary>
/// A model to represent an otac request
/// </summary>
public class OtacRequest
{
/// <summary>
/// The One Time Access Code
/// </summary>
public string Otac { get; set; }
/// <summary>
/// Should the user stay logged
/// </summary>
public bool StayLoggedIn { get; set; }
}
}

View File

@ -1,28 +0,0 @@
namespace Kyoo.Authentication.Models
{
/// <summary>
/// The main authentication options.
/// </summary>
public class AuthenticationOption
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "authentication";
/// <summary>
/// The options for certificates
/// </summary>
public CertificateOption Certificate { get; set; }
/// <summary>
/// Options for permissions
/// </summary>
public PermissionOption Permissions { get; set; }
/// <summary>
/// Root path of user's profile pictures.
/// </summary>
public string ProfilePicturePath { get; set; }
}
}

View File

@ -1,26 +0,0 @@
namespace Kyoo.Authentication.Models
{
/// <summary>
/// A typed option model for the certificate
/// </summary>
public class CertificateOption
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "authentication:certificate";
/// <summary>
/// The path of the certificate file.
/// </summary>
public string File { get; set; }
/// <summary>
/// The path of the old certificate file.
/// </summary>
public string OldFile { get; set; }
/// <summary>
/// The password of the certificates.
/// </summary>
public string Password { get; set; }
}
}

View File

@ -1,23 +0,0 @@
namespace Kyoo.Authentication.Models
{
/// <summary>
/// Permission options.
/// </summary>
public class PermissionOption
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "authentication:permissions";
/// <summary>
/// The default permissions that will be given to a non-connected user.
/// </summary>
public string[] Default { get; set; }
/// <summary>
/// Permissions applied to a new user.
/// </summary>
public string[] NewUser { get; set; }
}
}

View File

@ -1,35 +0,0 @@
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A permission validator that always validate permissions. This effectively disable the permission system.
/// </summary>
public class PassthroughPermissionValidator : IPermissionValidator
{
// ReSharper disable once SuggestBaseTypeForParameter
public PassthroughPermissionValidator(ILogger<PassthroughPermissionValidator> logger)
{
logger.LogWarning("No permission validator has been enabled, all users will have all permissions");
}
/// <inheritdoc />
public IFilterMetadata Create(PermissionAttribute attribute)
{
return new PassthroughValidator();
}
/// <inheritdoc />
public IFilterMetadata Create(PartialPermissionAttribute attribute)
{
return new PassthroughValidator();
}
/// <summary>
/// An useless filter that does nothing.
/// </summary>
private class PassthroughValidator : IFilterMetadata { }
}
}

View File

@ -1,23 +0,0 @@
namespace Kyoo.Core.Models.Options
{
/// <summary>
/// Options for media registering.
/// </summary>
public class MediaOptions
{
/// <summary>
/// The path of this options
/// </summary>
public const string Path = "Media";
/// <summary>
/// A regex for episodes
/// </summary>
public string[] Regex { get; set; }
/// <summary>
/// A regex for subtitles
/// </summary>
public string[] SubtitleRegex { get; set; }
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Kyoo.Core.Models.Options
{
/// <summary>
/// Options related to tasks
/// </summary>
public class TaskOptions
{
/// <summary>
/// The path of this options
/// </summary>
public const string Path = "Tasks";
/// <summary>
/// The number of tasks that can be run concurrently.
/// </summary>
public int Parallels { get; set; }
/// <summary>
/// The delay of tasks that should be automatically started at fixed times.
/// </summary>
[UsedImplicitly]
public Dictionary<string, TimeSpan> Scheduled { get; set; } = new();
}
}

View File

@ -1,156 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
namespace Kyoo.Core.Api
{
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
{
private int _depth = -1;
private string _host;
public JsonPropertyIgnorer(string host)
{
_host = host;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
LoadableRelationAttribute relation = member.GetCustomAttribute<LoadableRelationAttribute>();
if (relation != null)
{
if (relation.RelationID == null)
property.ShouldSerialize = x => _depth == 0 && member.GetValue(x) != null;
else
property.ShouldSerialize = x =>
{
if (_depth != 0)
return false;
if (member.GetValue(x) != null)
return true;
return x.GetType().GetProperty(relation.RelationID)?.GetValue(x) != null;
};
}
if (member.GetCustomAttribute<SerializeIgnoreAttribute>() != null)
property.ShouldSerialize = _ => false;
if (member.GetCustomAttribute<DeserializeIgnoreAttribute>() != null)
property.ShouldDeserialize = _ => false;
// TODO use http context to disable serialize as.
// TODO check https://stackoverflow.com/questions/53288633/net-core-api-custom-json-resolver-based-on-request-values
SerializeAsAttribute serializeAs = member.GetCustomAttribute<SerializeAsAttribute>();
if (serializeAs != null)
property.ValueProvider = new SerializeAsProvider(serializeAs.Format, _host);
return property;
}
protected override JsonContract CreateContract(Type objectType)
{
JsonContract contract = base.CreateContract(objectType);
if (Utility.GetGenericDefinition(objectType, typeof(Page<>)) == null
&& !objectType.IsAssignableTo(typeof(IEnumerable))
&& objectType.Name != "AnnotatedProblemDetails")
{
contract.OnSerializingCallbacks.Add((_, _) => _depth++);
contract.OnSerializedCallbacks.Add((_, _) => _depth--);
}
return contract;
}
}
public class PeopleRoleConverter : JsonConverter<PeopleRole>
{
public override void WriteJson(JsonWriter writer, PeopleRole value, JsonSerializer serializer)
{
ICollection<PeopleRole> oldPeople = value.Show?.People;
ICollection<PeopleRole> oldRoles = value.People?.Roles;
if (value.Show != null)
value.Show.People = null;
if (value.People != null)
value.People.Roles = null;
JObject obj = JObject.FromObject((value.ForPeople ? value.People : value.Show)!, serializer);
obj.Add("role", value.Role);
obj.Add("type", value.Type);
obj.WriteTo(writer);
if (value.Show != null)
value.Show.People = oldPeople;
if (value.People != null)
value.People.Roles = oldRoles;
}
public override PeopleRole ReadJson(JsonReader reader,
Type objectType,
PeopleRole existingValue,
bool hasExistingValue,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class SerializeAsProvider : IValueProvider
{
private string _format;
private string _host;
public SerializeAsProvider(string format, string host)
{
_format = format;
_host = host.TrimEnd('/');
}
public object GetValue(object target)
{
return Regex.Replace(_format, @"(?<!{){(\w+)(:(\w+))?}", x =>
{
string value = x.Groups[1].Value;
string modifier = x.Groups[3].Value;
if (value == "HOST")
return _host;
PropertyInfo properties = target.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(y => y.Name == value);
if (properties == null)
return null;
object objValue = properties.GetValue(target);
if (objValue is not string ret)
ret = objValue?.ToString();
if (ret == null)
throw new ArgumentException($"Invalid serializer replacement {value}");
foreach (char modification in modifier)
{
ret = modification switch
{
'l' => ret.ToLowerInvariant(),
'u' => ret.ToUpperInvariant(),
_ => throw new ArgumentException($"Invalid serializer modificator {modification}.")
};
}
return ret;
});
}
public void SetValue(object target, object value)
{
// Values are ignored and should not be editable, except if the internal value is set.
}
}
}

View File

@ -1,143 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
namespace Kyoo.Core.Api
{
[Route("subtitle")]
[ApiController]
public class SubtitleApi : ControllerBase
{
private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _files;
public SubtitleApi(ILibraryManager libraryManager, IFileSystem files)
{
_libraryManager = libraryManager;
_files = files;
}
[HttpGet("{id:int}")]
[Permission(nameof(SubtitleApi), Kind.Read)]
public async Task<IActionResult> GetSubtitle(int id)
{
Track subtitle = await _libraryManager.GetOrDefault<Track>(id);
return subtitle != null
? _files.FileResult(subtitle.Path)
: NotFound();
}
[HttpGet("{id:int}.{extension}")]
[Permission(nameof(SubtitleApi), Kind.Read)]
public async Task<IActionResult> GetSubtitle(int id, string extension)
{
Track subtitle = await _libraryManager.GetOrDefault<Track>(id);
if (subtitle == null)
return NotFound();
if (subtitle.Codec == "subrip" && extension == "vtt")
return new ConvertSubripToVtt(subtitle.Path, _files);
return _files.FileResult(subtitle.Path);
}
[HttpGet("{slug}")]
[Permission(nameof(SubtitleApi), Kind.Read)]
public async Task<IActionResult> GetSubtitle(string slug)
{
string extension = null;
if (slug.Count(x => x == '.') == 3)
{
int idx = slug.LastIndexOf('.');
extension = slug[(idx + 1)..];
slug = slug[..idx];
}
Track subtitle = await _libraryManager.GetOrDefault<Track>(Track.BuildSlug(slug, StreamType.Subtitle));
if (subtitle == null)
return NotFound();
if (subtitle.Codec == "subrip" && extension == "vtt")
return new ConvertSubripToVtt(subtitle.Path, _files);
return _files.FileResult(subtitle.Path);
}
}
public class ConvertSubripToVtt : IActionResult
{
private readonly string _path;
private readonly IFileSystem _files;
public ConvertSubripToVtt(string subtitlePath, IFileSystem files)
{
_path = subtitlePath;
_files = files;
}
public async Task ExecuteResultAsync(ActionContext context)
{
List<string> lines = new();
context.HttpContext.Response.StatusCode = 200;
context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
await using (StreamWriter writer = new(context.HttpContext.Response.Body))
{
await writer.WriteLineAsync("WEBVTT");
await writer.WriteLineAsync("");
await writer.WriteLineAsync("");
using StreamReader reader = new(await _files.GetReader(_path));
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (line == "")
{
lines.Add("");
IEnumerable<string> processedBlock = ConvertBlock(lines);
foreach (string t in processedBlock)
await writer.WriteLineAsync(t);
lines.Clear();
}
else
lines.Add(line);
}
}
await context.HttpContext.Response.Body.FlushAsync();
}
private static IEnumerable<string> ConvertBlock(IList<string> lines)
{
if (lines.Count < 3)
return lines;
lines[1] = lines[1].Replace(',', '.');
if (lines[2].Length > 5)
{
lines[1] += lines[2].Substring(0, 6) switch
{
"{\\an1}" => " line:93% position:15%",
"{\\an2}" => " line:93%",
"{\\an3}" => " line:93% position:85%",
"{\\an4}" => " line:50% position:15%",
"{\\an5}" => " line:50%",
"{\\an6}" => " line:50% position:85%",
"{\\an7}" => " line:7% position:15%",
"{\\an8}" => " line:7%",
"{\\an9}" => " line:7% position:85%",
_ => " line:93%"
};
}
if (lines[2].StartsWith("{\\an"))
lines[2] = lines[2].Substring(6);
return lines;
}
}
}

View File

@ -1,36 +0,0 @@
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Core.Api
{
[Route("api/watch")]
[ApiController]
public class WatchApi : ControllerBase
{
private readonly ILibraryManager _libraryManager;
public WatchApi(ILibraryManager libraryManager)
{
_libraryManager = libraryManager;
}
[HttpGet("{slug}")]
[Permission("video", Kind.Read)]
public async Task<ActionResult<WatchItem>> GetWatchItem(string slug)
{
try
{
Episode item = await _libraryManager.Get<Episode>(slug);
return await WatchItem.FromEpisode(item, _libraryManager);
}
catch (ItemNotFoundException)
{
return NotFound();
}
}
}
}

View File

@ -1,31 +0,0 @@
using System.Threading.Tasks;
using Kyoo.Core;
using Microsoft.AspNetCore.Hosting;
namespace Kyoo.Host.Console
{
/// <summary>
/// Program entrypoint.
/// </summary>
public static class Program
{
/// <summary>
/// The string representation of the environment used in <see cref="IWebHostEnvironment"/>.
/// </summary>
#if DEBUG
private const string Environment = "Development";
#else
private const string Environment = "Production";
#endif
/// <summary>
/// Main function of the program
/// </summary>
/// <param name="args">Command line arguments</param>
public static Task Main(string[] args)
{
Application application = new(Environment);
return application.Start(args);
}
}
}

View File

@ -1,12 +0,0 @@
<Project>
<PropertyGroup>
<IsWindows Condition="$([MSBuild]::IsOSPlatform('Windows'))">true</IsWindows>
</PropertyGroup>
<Import Project="Kyoo.Host.WindowsTrait.target" Condition="$(IsWindows) == true" />
<Import Project="Kyoo.Host.WindowsTrait.linux.target" Condition="$(IsWindows) != true" />
<ItemGroup>
<None Remove="*.target" />
</ItemGroup>
</Project>

View File

@ -1,26 +0,0 @@
<Project>
<!-- Project file used instead of the default csproj when the host system is not windows. This only skip the build. -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<NoWarn>NU1503</NoWarn>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="Build">
<Message Importance="high" Text="Detected current operating system is not windows, skipping WindowsHost build." />
</Target>
<Target Name="Clean" />
<Target Name="Pack" />
<Target Name="Restore" />
<Target Name="Publish" />
<ItemGroup>
<None Include="@(Compile)" />
<Compile Remove="*" />
</ItemGroup>
</Project>

View File

@ -1,32 +0,0 @@
using System.Threading.Tasks;
using Autofac;
using Kyoo.Core;
namespace Kyoo.Host.WindowsTrait
{
public static class Program
{
/// <summary>
/// The string representation of the environment used in IWebHostEnvironment.
/// </summary>
#if DEBUG
private const string Environment = "Development";
#else
private const string Environment = "Production";
#endif
/// <summary>
/// The main entry point for the application that overrides the default host.
/// It adds a system trait for windows and since the host is build as a windows executable instead of a console
/// app, the console is not showed.
/// </summary>
public static Task Main(string[] args)
{
Application application = new(Environment);
return application.Start(args, builder =>
{
builder.RegisterType<SystemTrait>().As<IStartable>().SingleInstance();
});
}
}
}

View File

@ -1,846 +0,0 @@
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Postgresql.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:item_type", "show,movie,collection")
.Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned")
.Annotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,attachment");
migrationBuilder.CreateTable(
name: "collections",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
overview = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_collections", x => x.id);
});
migrationBuilder.CreateTable(
name: "genres",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_genres", x => x.id);
});
migrationBuilder.CreateTable(
name: "libraries",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
paths = table.Column<string[]>(type: "text[]", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_libraries", x => x.id);
});
migrationBuilder.CreateTable(
name: "people",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_people", x => x.id);
});
migrationBuilder.CreateTable(
name: "providers",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_providers", x => x.id);
});
migrationBuilder.CreateTable(
name: "studios",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_studios", x => x.id);
});
migrationBuilder.CreateTable(
name: "users",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
username = table.Column<string>(type: "text", nullable: true),
email = table.Column<string>(type: "text", nullable: true),
password = table.Column<string>(type: "text", nullable: true),
permissions = table.Column<string[]>(type: "text[]", nullable: true),
extra_data = table.Column<Dictionary<string, string>>(type: "jsonb", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_users", x => x.id);
});
migrationBuilder.CreateTable(
name: "link_library_collection",
columns: table => new
{
collection_id = table.Column<int>(type: "integer", nullable: false),
library_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_library_collection", x => new { x.collection_id, x.library_id });
table.ForeignKey(
name: "fk_link_library_collection_collections_collection_id",
column: x => x.collection_id,
principalTable: "collections",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_library_collection_libraries_library_id",
column: x => x.library_id,
principalTable: "libraries",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "collection_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_collection_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_collection_metadata_id_collections_collection_id",
column: x => x.resource_id,
principalTable: "collections",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_collection_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "link_library_provider",
columns: table => new
{
library_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_library_provider", x => new { x.library_id, x.provider_id });
table.ForeignKey(
name: "fk_link_library_provider_libraries_library_id",
column: x => x.library_id,
principalTable: "libraries",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_library_provider_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "people_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_people_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_people_metadata_id_people_people_id",
column: x => x.resource_id,
principalTable: "people",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_people_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "shows",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: false),
title = table.Column<string>(type: "text", nullable: true),
aliases = table.Column<string[]>(type: "text[]", nullable: true),
path = table.Column<string>(type: "text", nullable: true),
overview = table.Column<string>(type: "text", nullable: true),
status = table.Column<Status>(type: "status", nullable: false),
start_air = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
end_air = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
is_movie = table.Column<bool>(type: "boolean", nullable: false),
studio_id = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_shows", x => x.id);
table.ForeignKey(
name: "fk_shows_studios_studio_id",
column: x => x.studio_id,
principalTable: "studios",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "studio_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_studio_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_studio_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_studio_metadata_id_studios_studio_id",
column: x => x.resource_id,
principalTable: "studios",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "link_collection_show",
columns: table => new
{
collection_id = table.Column<int>(type: "integer", nullable: false),
show_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_collection_show", x => new { x.collection_id, x.show_id });
table.ForeignKey(
name: "fk_link_collection_show_collections_collection_id",
column: x => x.collection_id,
principalTable: "collections",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_collection_show_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "link_library_show",
columns: table => new
{
library_id = table.Column<int>(type: "integer", nullable: false),
show_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_library_show", x => new { x.library_id, x.show_id });
table.ForeignKey(
name: "fk_link_library_show_libraries_library_id",
column: x => x.library_id,
principalTable: "libraries",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_library_show_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "link_show_genre",
columns: table => new
{
genre_id = table.Column<int>(type: "integer", nullable: false),
show_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_show_genre", x => new { x.genre_id, x.show_id });
table.ForeignKey(
name: "fk_link_show_genre_genres_genre_id",
column: x => x.genre_id,
principalTable: "genres",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_show_genre_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "link_user_show",
columns: table => new
{
users_id = table.Column<int>(type: "integer", nullable: false),
watched_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_link_user_show", x => new { x.users_id, x.watched_id });
table.ForeignKey(
name: "fk_link_user_show_shows_watched_id",
column: x => x.watched_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_link_user_show_users_users_id",
column: x => x.users_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "people_roles",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
people_id = table.Column<int>(type: "integer", nullable: false),
show_id = table.Column<int>(type: "integer", nullable: false),
type = table.Column<string>(type: "text", nullable: true),
role = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_people_roles", x => x.id);
table.ForeignKey(
name: "fk_people_roles_people_people_id",
column: x => x.people_id,
principalTable: "people",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_people_roles_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "seasons",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: true),
show_id = table.Column<int>(type: "integer", nullable: false),
season_number = table.Column<int>(type: "integer", nullable: false),
title = table.Column<string>(type: "text", nullable: true),
overview = table.Column<string>(type: "text", nullable: true),
start_date = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
end_date = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_seasons", x => x.id);
table.ForeignKey(
name: "fk_seasons_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "show_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_show_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_show_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_show_metadata_id_shows_show_id",
column: x => x.resource_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "episodes",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: true),
show_id = table.Column<int>(type: "integer", nullable: false),
season_id = table.Column<int>(type: "integer", nullable: true),
season_number = table.Column<int>(type: "integer", nullable: true),
episode_number = table.Column<int>(type: "integer", nullable: true),
absolute_number = table.Column<int>(type: "integer", nullable: true),
path = table.Column<string>(type: "text", nullable: true),
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
title = table.Column<string>(type: "text", nullable: true),
overview = table.Column<string>(type: "text", nullable: true),
release_date = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_episodes", x => x.id);
table.ForeignKey(
name: "fk_episodes_seasons_season_id",
column: x => x.season_id,
principalTable: "seasons",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_episodes_shows_show_id",
column: x => x.show_id,
principalTable: "shows",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "season_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_season_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_season_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_season_metadata_id_seasons_season_id",
column: x => x.resource_id,
principalTable: "seasons",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "episode_metadata_id",
columns: table => new
{
resource_id = table.Column<int>(type: "integer", nullable: false),
provider_id = table.Column<int>(type: "integer", nullable: false),
data_id = table.Column<string>(type: "text", nullable: true),
link = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_episode_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
name: "fk_episode_metadata_id_episodes_episode_id",
column: x => x.resource_id,
principalTable: "episodes",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_episode_metadata_id_providers_provider_id",
column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "tracks",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column<string>(type: "text", nullable: true),
title = table.Column<string>(type: "text", nullable: true),
language = table.Column<string>(type: "text", nullable: true),
codec = table.Column<string>(type: "text", nullable: true),
is_default = table.Column<bool>(type: "boolean", nullable: false),
is_forced = table.Column<bool>(type: "boolean", nullable: false),
is_external = table.Column<bool>(type: "boolean", nullable: false),
path = table.Column<string>(type: "text", nullable: true),
type = table.Column<StreamType>(type: "stream_type", nullable: false),
episode_id = table.Column<int>(type: "integer", nullable: false),
track_index = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_tracks", x => x.id);
table.ForeignKey(
name: "fk_tracks_episodes_episode_id",
column: x => x.episode_id,
principalTable: "episodes",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "watched_episodes",
columns: table => new
{
user_id = table.Column<int>(type: "integer", nullable: false),
episode_id = table.Column<int>(type: "integer", nullable: false),
watched_percentage = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_watched_episodes", x => new { x.user_id, x.episode_id });
table.ForeignKey(
name: "fk_watched_episodes_episodes_episode_id",
column: x => x.episode_id,
principalTable: "episodes",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_watched_episodes_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_collection_metadata_id_provider_id",
table: "collection_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_collections_slug",
table: "collections",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_episode_metadata_id_provider_id",
table: "episode_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_episodes_season_id",
table: "episodes",
column: "season_id");
migrationBuilder.CreateIndex(
name: "ix_episodes_show_id_season_number_episode_number_absolute_numb",
table: "episodes",
columns: new[] { "show_id", "season_number", "episode_number", "absolute_number" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_episodes_slug",
table: "episodes",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_genres_slug",
table: "genres",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_libraries_slug",
table: "libraries",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_link_collection_show_show_id",
table: "link_collection_show",
column: "show_id");
migrationBuilder.CreateIndex(
name: "ix_link_library_collection_library_id",
table: "link_library_collection",
column: "library_id");
migrationBuilder.CreateIndex(
name: "ix_link_library_provider_provider_id",
table: "link_library_provider",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_link_library_show_show_id",
table: "link_library_show",
column: "show_id");
migrationBuilder.CreateIndex(
name: "ix_link_show_genre_show_id",
table: "link_show_genre",
column: "show_id");
migrationBuilder.CreateIndex(
name: "ix_link_user_show_watched_id",
table: "link_user_show",
column: "watched_id");
migrationBuilder.CreateIndex(
name: "ix_people_slug",
table: "people",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_people_metadata_id_provider_id",
table: "people_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_people_roles_people_id",
table: "people_roles",
column: "people_id");
migrationBuilder.CreateIndex(
name: "ix_people_roles_show_id",
table: "people_roles",
column: "show_id");
migrationBuilder.CreateIndex(
name: "ix_providers_slug",
table: "providers",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_season_metadata_id_provider_id",
table: "season_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_seasons_show_id_season_number",
table: "seasons",
columns: new[] { "show_id", "season_number" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_seasons_slug",
table: "seasons",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_show_metadata_id_provider_id",
table: "show_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_shows_slug",
table: "shows",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_shows_studio_id",
table: "shows",
column: "studio_id");
migrationBuilder.CreateIndex(
name: "ix_studio_metadata_id_provider_id",
table: "studio_metadata_id",
column: "provider_id");
migrationBuilder.CreateIndex(
name: "ix_studios_slug",
table: "studios",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_tracks_episode_id_type_language_track_index_is_forced",
table: "tracks",
columns: new[] { "episode_id", "type", "language", "track_index", "is_forced" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_tracks_slug",
table: "tracks",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_users_slug",
table: "users",
column: "slug",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_watched_episodes_episode_id",
table: "watched_episodes",
column: "episode_id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "collection_metadata_id");
migrationBuilder.DropTable(
name: "episode_metadata_id");
migrationBuilder.DropTable(
name: "link_collection_show");
migrationBuilder.DropTable(
name: "link_library_collection");
migrationBuilder.DropTable(
name: "link_library_provider");
migrationBuilder.DropTable(
name: "link_library_show");
migrationBuilder.DropTable(
name: "link_show_genre");
migrationBuilder.DropTable(
name: "link_user_show");
migrationBuilder.DropTable(
name: "people_metadata_id");
migrationBuilder.DropTable(
name: "people_roles");
migrationBuilder.DropTable(
name: "season_metadata_id");
migrationBuilder.DropTable(
name: "show_metadata_id");
migrationBuilder.DropTable(
name: "studio_metadata_id");
migrationBuilder.DropTable(
name: "tracks");
migrationBuilder.DropTable(
name: "watched_episodes");
migrationBuilder.DropTable(
name: "collections");
migrationBuilder.DropTable(
name: "libraries");
migrationBuilder.DropTable(
name: "genres");
migrationBuilder.DropTable(
name: "people");
migrationBuilder.DropTable(
name: "providers");
migrationBuilder.DropTable(
name: "episodes");
migrationBuilder.DropTable(
name: "users");
migrationBuilder.DropTable(
name: "seasons");
migrationBuilder.DropTable(
name: "shows");
migrationBuilder.DropTable(
name: "studios");
}
}
}

View File

@ -1,838 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Kyoo.SqLite.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Genres",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Genres", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Libraries",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Paths = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Libraries", x => x.ID);
});
migrationBuilder.CreateTable(
name: "People",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_People", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Providers",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Providers", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Studios",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Studios", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Username = table.Column<string>(type: "TEXT", nullable: true),
Email = table.Column<string>(type: "TEXT", nullable: true),
Password = table.Column<string>(type: "TEXT", nullable: true),
Permissions = table.Column<string>(type: "TEXT", nullable: true),
ExtraData = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.ID);
});
migrationBuilder.CreateTable(
name: "LinkLibraryCollection",
columns: table => new
{
CollectionID = table.Column<int>(type: "INTEGER", nullable: false),
LibraryID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryCollection", x => new { x.CollectionID, x.LibraryID });
table.ForeignKey(
name: "FK_LinkLibraryCollection_Collections_CollectionID",
column: x => x.CollectionID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryCollection_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CollectionMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CollectionMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_CollectionMetadataID_Collections_ResourceID",
column: x => x.ResourceID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CollectionMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkLibraryProvider",
columns: table => new
{
LibraryID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryProvider", x => new { x.LibraryID, x.ProviderID });
table.ForeignKey(
name: "FK_LinkLibraryProvider_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryProvider_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "PeopleMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PeopleMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_PeopleMetadataID_People_ResourceID",
column: x => x.ResourceID,
principalTable: "People",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_PeopleMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Shows",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: true),
Aliases = table.Column<string>(type: "TEXT", nullable: true),
Path = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
Status = table.Column<int>(type: "INTEGER", nullable: false),
StartAir = table.Column<DateTime>(type: "TEXT", nullable: true),
EndAir = table.Column<DateTime>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
IsMovie = table.Column<bool>(type: "INTEGER", nullable: false),
StudioID = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Shows", x => x.ID);
table.ForeignKey(
name: "FK_Shows_Studios_StudioID",
column: x => x.StudioID,
principalTable: "Studios",
principalColumn: "ID",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "StudioMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_StudioMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_StudioMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_StudioMetadataID_Studios_ResourceID",
column: x => x.ResourceID,
principalTable: "Studios",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkCollectionShow",
columns: table => new
{
CollectionID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkCollectionShow", x => new { x.CollectionID, x.ShowID });
table.ForeignKey(
name: "FK_LinkCollectionShow_Collections_CollectionID",
column: x => x.CollectionID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkCollectionShow_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkLibraryShow",
columns: table => new
{
LibraryID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryShow", x => new { x.LibraryID, x.ShowID });
table.ForeignKey(
name: "FK_LinkLibraryShow_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryShow_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkShowGenre",
columns: table => new
{
GenreID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkShowGenre", x => new { x.GenreID, x.ShowID });
table.ForeignKey(
name: "FK_LinkShowGenre_Genres_GenreID",
column: x => x.GenreID,
principalTable: "Genres",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkShowGenre_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkUserShow",
columns: table => new
{
UsersID = table.Column<int>(type: "INTEGER", nullable: false),
WatchedID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkUserShow", x => new { x.UsersID, x.WatchedID });
table.ForeignKey(
name: "FK_LinkUserShow_Shows_WatchedID",
column: x => x.WatchedID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkUserShow_Users_UsersID",
column: x => x.UsersID,
principalTable: "Users",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "PeopleRoles",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
PeopleID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
Type = table.Column<string>(type: "TEXT", nullable: true),
Role = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PeopleRoles", x => x.ID);
table.ForeignKey(
name: "FK_PeopleRoles_People_PeopleID",
column: x => x.PeopleID,
principalTable: "People",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_PeopleRoles_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Seasons",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
SeasonNumber = table.Column<int>(type: "INTEGER", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
StartDate = table.Column<DateTime>(type: "TEXT", nullable: true),
EndDate = table.Column<DateTime>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Seasons", x => x.ID);
table.ForeignKey(
name: "FK_Seasons_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ShowMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ShowMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_ShowMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ShowMetadataID_Shows_ResourceID",
column: x => x.ResourceID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Episodes",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
SeasonID = table.Column<int>(type: "INTEGER", nullable: true),
SeasonNumber = table.Column<int>(type: "INTEGER", nullable: true),
EpisodeNumber = table.Column<int>(type: "INTEGER", nullable: true),
AbsoluteNumber = table.Column<int>(type: "INTEGER", nullable: true),
Path = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
Title = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Episodes", x => x.ID);
table.ForeignKey(
name: "FK_Episodes_Seasons_SeasonID",
column: x => x.SeasonID,
principalTable: "Seasons",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Episodes_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "SeasonMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SeasonMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_SeasonMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_SeasonMetadataID_Seasons_ResourceID",
column: x => x.ResourceID,
principalTable: "Seasons",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EpisodeMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EpisodeMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_EpisodeMetadataID_Episodes_ResourceID",
column: x => x.ResourceID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_EpisodeMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Tracks",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
Title = table.Column<string>(type: "TEXT", nullable: true),
Language = table.Column<string>(type: "TEXT", nullable: true),
Codec = table.Column<string>(type: "TEXT", nullable: true),
IsDefault = table.Column<bool>(type: "INTEGER", nullable: false),
IsForced = table.Column<bool>(type: "INTEGER", nullable: false),
IsExternal = table.Column<bool>(type: "INTEGER", nullable: false),
Path = table.Column<string>(type: "TEXT", nullable: true),
Type = table.Column<int>(type: "INTEGER", nullable: false),
EpisodeID = table.Column<int>(type: "INTEGER", nullable: false),
TrackIndex = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tracks", x => x.ID);
table.ForeignKey(
name: "FK_Tracks_Episodes_EpisodeID",
column: x => x.EpisodeID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "WatchedEpisodes",
columns: table => new
{
UserID = table.Column<int>(type: "INTEGER", nullable: false),
EpisodeID = table.Column<int>(type: "INTEGER", nullable: false),
WatchedPercentage = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_WatchedEpisodes", x => new { x.UserID, x.EpisodeID });
table.ForeignKey(
name: "FK_WatchedEpisodes_Episodes_EpisodeID",
column: x => x.EpisodeID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_WatchedEpisodes_Users_UserID",
column: x => x.UserID,
principalTable: "Users",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_CollectionMetadataID_ProviderID",
table: "CollectionMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Collections_Slug",
table: "Collections",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_EpisodeMetadataID_ProviderID",
table: "EpisodeMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Episodes_SeasonID",
table: "Episodes",
column: "SeasonID");
migrationBuilder.CreateIndex(
name: "IX_Episodes_ShowID_SeasonNumber_EpisodeNumber_AbsoluteNumber",
table: "Episodes",
columns: new[] { "ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Episodes_Slug",
table: "Episodes",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Genres_Slug",
table: "Genres",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Libraries_Slug",
table: "Libraries",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_LinkCollectionShow_ShowID",
table: "LinkCollectionShow",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryCollection_LibraryID",
table: "LinkLibraryCollection",
column: "LibraryID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryProvider_ProviderID",
table: "LinkLibraryProvider",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryShow_ShowID",
table: "LinkLibraryShow",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkShowGenre_ShowID",
table: "LinkShowGenre",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkUserShow_WatchedID",
table: "LinkUserShow",
column: "WatchedID");
migrationBuilder.CreateIndex(
name: "IX_People_Slug",
table: "People",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_PeopleMetadataID_ProviderID",
table: "PeopleMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_PeopleRoles_PeopleID",
table: "PeopleRoles",
column: "PeopleID");
migrationBuilder.CreateIndex(
name: "IX_PeopleRoles_ShowID",
table: "PeopleRoles",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_Providers_Slug",
table: "Providers",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_SeasonMetadataID_ProviderID",
table: "SeasonMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Seasons_ShowID_SeasonNumber",
table: "Seasons",
columns: new[] { "ShowID", "SeasonNumber" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Seasons_Slug",
table: "Seasons",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ShowMetadataID_ProviderID",
table: "ShowMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Shows_Slug",
table: "Shows",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Shows_StudioID",
table: "Shows",
column: "StudioID");
migrationBuilder.CreateIndex(
name: "IX_StudioMetadataID_ProviderID",
table: "StudioMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Studios_Slug",
table: "Studios",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Tracks_EpisodeID_Type_Language_TrackIndex_IsForced",
table: "Tracks",
columns: new[] { "EpisodeID", "Type", "Language", "TrackIndex", "IsForced" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Tracks_Slug",
table: "Tracks",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_Slug",
table: "Users",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_WatchedEpisodes_EpisodeID",
table: "WatchedEpisodes",
column: "EpisodeID");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CollectionMetadataID");
migrationBuilder.DropTable(
name: "EpisodeMetadataID");
migrationBuilder.DropTable(
name: "LinkCollectionShow");
migrationBuilder.DropTable(
name: "LinkLibraryCollection");
migrationBuilder.DropTable(
name: "LinkLibraryProvider");
migrationBuilder.DropTable(
name: "LinkLibraryShow");
migrationBuilder.DropTable(
name: "LinkShowGenre");
migrationBuilder.DropTable(
name: "LinkUserShow");
migrationBuilder.DropTable(
name: "PeopleMetadataID");
migrationBuilder.DropTable(
name: "PeopleRoles");
migrationBuilder.DropTable(
name: "SeasonMetadataID");
migrationBuilder.DropTable(
name: "ShowMetadataID");
migrationBuilder.DropTable(
name: "StudioMetadataID");
migrationBuilder.DropTable(
name: "Tracks");
migrationBuilder.DropTable(
name: "WatchedEpisodes");
migrationBuilder.DropTable(
name: "Collections");
migrationBuilder.DropTable(
name: "Libraries");
migrationBuilder.DropTable(
name: "Genres");
migrationBuilder.DropTable(
name: "People");
migrationBuilder.DropTable(
name: "Providers");
migrationBuilder.DropTable(
name: "Episodes");
migrationBuilder.DropTable(
name: "Users");
migrationBuilder.DropTable(
name: "Seasons");
migrationBuilder.DropTable(
name: "Shows");
migrationBuilder.DropTable(
name: "Studios");
}
}
}

View File

@ -1,18 +0,0 @@
namespace Kyoo.TheMovieDb.Models
{
/// <summary>
/// The option containing the api key for TheMovieDb.
/// </summary>
public class TheMovieDbOptions
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "the-moviedb";
/// <summary>
/// The api key of TheMovieDb.
/// </summary>
public string ApiKey { get; set; }
}
}

View File

@ -1,18 +0,0 @@
namespace Kyoo.TheTvdb.Models
{
/// <summary>
/// The option containing the api key for the tvdb.
/// </summary>
public class TvdbOption
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "tvdb";
/// <summary>
/// The api key of the tvdb.
/// </summary>
public string ApiKey { get; set; }
}
}

44
Kyoo.ruleset Normal file
View File

@ -0,0 +1,44 @@
<RuleSet Name="Kyoo" ToolsVersion="10.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.MaintainabilityRules">
<Rule Id="SA1413" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
<Rule Id="SA1414" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.OrderingRules">
<Rule Id="SA1201" Action="None" /> <!-- ElementsMustAppearInTheCorrectOrder -->
<Rule Id="SA1202" Action="None" /> <!-- ElementsMustBeOrderedByAccess -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.NamingRules">
<Rule Id="SA1309" Action="None" /> <!-- FieldNamesMustNotBeginWithUnderscore -->
<Rule Id="SX1309" Action="Warning" /> <!-- FieldNamesMustBeginWithUnderscore -->
<Rule Id="SA1300" Action="None" /> <!-- ElementMustBeginWithUpperCaseLetter (this conflict with the _ prefix for privates, enforced by an IDE rule) -->
<Rule Id="SA1316" Action="None" /> <!-- TupleElementNamesShouldUseCorrectCasing (should be camels when deconstructing but pascal otherwise. -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.ReadabilityRules">
<Rule Id="SA1101" Action="None" /> <!-- PrefixLocalCallsWithThis -->
<Rule Id="SX1101" Action="Warning" /> <!-- DoNotPrefixLocalMembersWithThis -->
<Rule Id="SA1134" Action="None" /> <!-- AttributesMustNotShareLine -->
<Rule Id="SA1117" Action="None" /> <!-- ParametersMustBeOnSameLineOrSeparateLines -->
<Rule Id="SA1116" Action="None" /> <!-- SplitParametersMustStartOnLineAfterDeclaration -->
<Rule Id="SA1111" Action="None" /> <!-- ClosingParenthesisMustBeOnLineOfLastParameter -->
<Rule Id="SA1009" Action="None" /> <!-- ClosingParenthesisMustBeSpacedCorrectly (bugged if the parenthesis is on a line by iteself) -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.SpacingRules">
<Rule Id="SA1502" Action="None"/> <!-- DocumentationLinesMustBeginWithSingleSpace -->
<Rule Id="SA1027" Action="None"/> <!-- UseTabsCorrectly (smarts tabs are broken). TODO find a way to enable smart tabs -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.LayoutRules">
<Rule Id="SA1503" Action="None"/> <!-- BracesMustNotBeOmitted -->
<Rule Id="SA1520" Action="None"/> <!-- UseBracesConsistently -->
<Rule Id="SA1515" Action="None"/> <!-- SingleLineCommentMustBePrecededByBlankLine -->
<Rule Id="SA1513" Action="None"/> <!-- ClosingBraceMustBeFollowedByBlankLine -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.DocumentationRules">
<Rule Id="SA1642" Action="None" /> <!-- ConstructorSummaryDocumentationMustBeginWithStandardText -->
<Rule Id="SA1643" Action="None" /> <!-- DestructorSummaryDocumentationMustBeginWithStandardText -->
<Rule Id="SA1623" Action="None" /> <!-- PropertySummaryDocumentationMustMatchAccessors -->
<Rule Id="SA1629" Action="None" /> <!-- DocumentationTextMustEndWithAPeriod TODO remove this, this is only temporary -->
</Rules>
</RuleSet>

View File

@ -1,27 +1,27 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "Kyoo.Core\Kyoo.Core.csproj", "{0F8275B6-C7DD-42DF-A168-755C81B1C329}"
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "src\Kyoo.Core\Kyoo.Core.csproj", "{0F8275B6-C7DD-42DF-A168-755C81B1C329}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "src\Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Database", "Kyoo.Database\Kyoo.Database.csproj", "{6F91B645-F785-46BB-9C4F-1EFC83E489B6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Database", "src\Kyoo.Database\Kyoo.Database.csproj", "{6F91B645-F785-46BB-9C4F-1EFC83E489B6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "src\Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "src\Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "src\Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheMovieDb", "Kyoo.TheMovieDb\Kyoo.TheMovieDb.csproj", "{BAB270D4-E0EA-4329-BA65-512FDAB01001}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheMovieDb", "src\Kyoo.TheMovieDb\Kyoo.TheMovieDb.csproj", "{BAB270D4-E0EA-4329-BA65-512FDAB01001}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "tests\Kyoo.Tests\Kyoo.Tests.csproj", "{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.WebApp", "Kyoo.WebApp\Kyoo.WebApp.csproj", "{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.WebApp", "src\Kyoo.WebApp\Kyoo.WebApp.csproj", "{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.WindowsTrait", "Kyoo.Host.WindowsTrait\Kyoo.Host.WindowsTrait.csproj", "{98851001-40DD-46A6-94B3-2F8D90722076}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.WindowsTrait", "src\Kyoo.Host.WindowsTrait\Kyoo.Host.WindowsTrait.csproj", "{98851001-40DD-46A6-94B3-2F8D90722076}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Console", "Kyoo.Host.Console\Kyoo.Host.Console.csproj", "{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Console", "src\Kyoo.Host.Console\Kyoo.Host.Console.csproj", "{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

29
src/Directory.Build.props Normal file
View File

@ -0,0 +1,29 @@
<Project>
<PropertyGroup>
<IsWindows Condition="$([MSBuild]::IsOSPlatform('Windows'))">true</IsWindows>
<IsOSX Condition="$([MSBuild]::IsOSPlatform('OSX'))">true</IsOSX>
<IsLinux Condition="$([MSBuild]::IsOSPlatform('Linux'))">true</IsLinux>
<!-- TODO the next thing does not work on rider, enabling coding style check by default. -->
<!--<CheckCodingStyle Condition="$(BuildingInsideVisualStudio) == true">true</CheckCodingStyle>-->
<!--<CheckCodingStyle Condition="$(BuildingInsideReSharper) == true">true</CheckCodingStyle>-->
<CheckCodingStyle Condition="$(CheckCodingStyle) == ''">true</CheckCodingStyle>
</PropertyGroup>
<ItemGroup Condition="$(CheckCodingStyle) == true">
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.354" PrivateAssets="All" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)../stylecop.json" Link="stylecop.json" Visible="false" />
<None Include="$(MSBuildThisFileDirectory)../.editorconfig" Link=".editorconfig" Visible="false" />
</ItemGroup>
<PropertyGroup Condition="$(CheckCodingStyle) == true">
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>CS1591;SA1600;SA1601</NoWarn>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)../Kyoo.ruleset</CodeAnalysisRuleSet>
<!-- <AnalysisMode>AllEnabledByDefault</AnalysisMode>-->
</PropertyGroup>
</Project>

View File

@ -0,0 +1,49 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// An interface that allow one to interact with the host and shutdown or restart the app.
/// </summary>
public interface IApplication
{
/// <summary>
/// Shutdown the process and stop gracefully.
/// </summary>
void Shutdown();
/// <summary>
/// Restart Kyoo from scratch, reload plugins, configurations and restart the web server.
/// </summary>
void Restart();
/// <summary>
/// Get the data directory.
/// </summary>
/// <returns>Retrieve the data directory where runtime data should be stored.</returns>
string GetDataDirectory();
/// <summary>
/// Retrieve the path of the json configuration file
/// (relative to the data directory, see <see cref="GetDataDirectory"/>).
/// </summary>
/// <returns>The configuration file name.</returns>
string GetConfigFile();
}
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -14,10 +32,10 @@ namespace Kyoo.Abstractions.Controllers
public interface IConfigurationManager
{
/// <summary>
/// Add an editable configuration to the editable configuration list
/// Add an editable configuration to the editable configuration list.
/// </summary>
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
/// <typeparam name="T">The type of the configuration</typeparam>
/// <typeparam name="T">The type of the configuration.</typeparam>
void AddTyped<T>(string path);
/// <summary>
@ -40,28 +58,29 @@ namespace Kyoo.Abstractions.Controllers
/// <summary>
/// Get the value of a setting using it's path.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__')</param>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated</returns>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
object GetValue(string path);
/// <summary>
/// Get the value of a setting using it's path.
/// If your don't need a strongly typed value, see <see cref="GetValue"/>.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__')</param>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <typeparam name="T">A type to strongly type your option.</typeparam>
/// <exception cref="InvalidCastException">If your type is not the same as the registered type</exception>
/// <exception cref="InvalidCastException">If your type is not the same as the registered type.</exception>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated</returns>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
T GetValue<T>(string path);
/// <summary>
/// Edit the value of a setting using it's path. Save it to the json file.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__')</param>
/// <param name="value">The new value of the resource</param>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <param name="value">The new value of the resource.</param>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task EditValue(string path, object value);
}
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@ -8,7 +26,8 @@ using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Abstractions.Controllers
{
/// <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>
public interface IFileSystem
{
@ -16,7 +35,7 @@ namespace Kyoo.Abstractions.Controllers
/// <summary>
/// Used for http queries returning a file. This should be used to return local files
/// or proxy them from a distant server
/// or proxy them from a distant server.
/// </summary>
/// <remarks>
/// If no file exists at the given path or if the path is null, a NotFoundResult is returned

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System.Threading.Tasks;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
@ -10,7 +28,7 @@ using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// An interface to interract with the database. Every repository is mapped through here.
/// An interface to interact with the database. Every repository is mapped through here.
/// </summary>
public interface ILibraryManager
{
@ -20,7 +38,8 @@ namespace Kyoo.Abstractions.Controllers
/// <typeparam name="T">The type you want</typeparam>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The repository corresponding</returns>
IRepository<T> GetRepository<T>() where T : class, IResource;
IRepository<T> GetRepository<T>()
where T : class, IResource;
/// <summary>
/// The repository that handle libraries.
@ -28,7 +47,7 @@ namespace Kyoo.Abstractions.Controllers
ILibraryRepository LibraryRepository { get; }
/// <summary>
/// The repository that handle libraries's items (a wrapper arround shows & collections).
/// The repository that handle libraries items (a wrapper around shows and collections).
/// </summary>
ILibraryItemRepository LibraryItemRepository { get; }
@ -90,7 +109,8 @@ namespace Kyoo.Abstractions.Controllers
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The resource found</returns>
[ItemNotNull]
Task<T> Get<T>(int id) where T : class, IResource;
Task<T> Get<T>(int id)
where T : class, IResource;
/// <summary>
/// Get the resource by it's slug
@ -100,7 +120,8 @@ namespace Kyoo.Abstractions.Controllers
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The resource found</returns>
[ItemNotNull]
Task<T> Get<T>(string slug) where T : class, IResource;
Task<T> Get<T>(string slug)
where T : class, IResource;
/// <summary>
/// Get the resource by a filter function.
@ -110,7 +131,8 @@ namespace Kyoo.Abstractions.Controllers
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The first resource found that match the where function</returns>
[ItemNotNull]
Task<T> Get<T>(Expression<Func<T, bool>> where) where T : class, IResource;
Task<T> Get<T>(Expression<Func<T, bool>> where)
where T : class, IResource;
/// <summary>
/// Get a season from it's showID and it's seasonNumber
@ -161,7 +183,8 @@ namespace Kyoo.Abstractions.Controllers
/// <typeparam name="T">The type of the resource</typeparam>
/// <returns>The resource found</returns>
[ItemCanBeNull]
Task<T> GetOrDefault<T>(int id) where T : class, IResource;
Task<T> GetOrDefault<T>(int id)
where T : class, IResource;
/// <summary>
/// Get the resource by it's slug or null if it is not found.
@ -170,7 +193,8 @@ namespace Kyoo.Abstractions.Controllers
/// <typeparam name="T">The type of the resource</typeparam>
/// <returns>The resource found</returns>
[ItemCanBeNull]
Task<T> GetOrDefault<T>(string slug) where T : class, IResource;
Task<T> GetOrDefault<T>(string slug)
where T : class, IResource;
/// <summary>
/// Get the resource by a filter function or null if it is not found.
@ -179,7 +203,8 @@ namespace Kyoo.Abstractions.Controllers
/// <typeparam name="T">The type of the resource</typeparam>
/// <returns>The first resource found that match the where function</returns>
[ItemCanBeNull]
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where) where T : class, IResource;
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where)
where T : class, IResource;
/// <summary>
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
@ -219,7 +244,6 @@ namespace Kyoo.Abstractions.Controllers
[ItemCanBeNull]
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
/// <summary>
/// Load a related resource
/// </summary>
@ -230,9 +254,9 @@ namespace Kyoo.Abstractions.Controllers
/// </param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <typeparam name="T2">The related resource's type</typeparam>
/// <returns>The param <see cref="obj"/></returns>
/// <returns>The param <paramref name="obj"/></returns>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
/// <seealso cref="Load{T}(T, System.String, bool)"/>
/// <seealso cref="Load{T}(T, string, bool)"/>
/// <seealso cref="Load(IResource, string, bool)"/>
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, T2>> member, bool force = false)
where T : class, IResource
@ -248,9 +272,9 @@ namespace Kyoo.Abstractions.Controllers
/// </param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <typeparam name="T2">The related resource's type</typeparam>
/// <returns>The param <see cref="obj"/></returns>
/// <returns>The param <paramref name="obj"/></returns>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
/// <seealso cref="Load{T}(T, System.String, bool)"/>
/// <seealso cref="Load{T}(T, string, bool)"/>
/// <seealso cref="Load(IResource, string, bool)"/>
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
where T : class, IResource
@ -265,7 +289,7 @@ namespace Kyoo.Abstractions.Controllers
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
/// </param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <returns>The param <see cref="obj"/></returns>
/// <returns>The param <paramref name="obj"/></returns>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
/// <seealso cref="Load(IResource, string, bool)"/>
@ -273,7 +297,7 @@ namespace Kyoo.Abstractions.Controllers
where T : class, IResource;
/// <summary>
/// Load a related resource without specifing it's type.
/// Load a related resource without specifying it's type.
/// </summary>
/// <param name="obj">The source object.</param>
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
@ -282,15 +306,16 @@ namespace Kyoo.Abstractions.Controllers
/// </param>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
/// <seealso cref="Load{T}(T, System.String, bool)"/>
/// <seealso cref="Load{T}(T, string, bool)"/>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Load([NotNull] IResource obj, string memberName, bool force = false);
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
/// <param name="id">The ID of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
@ -299,7 +324,7 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default);
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
/// <param name="id">The ID of the library</param>
/// <param name="where">A filter function</param>
@ -313,11 +338,11 @@ namespace Kyoo.Abstractions.Controllers
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
/// <param name="slug">The slug of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
@ -326,7 +351,7 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default);
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
/// <param name="slug">The slug of the library</param>
/// <param name="where">A filter function</param>
@ -339,13 +364,12 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default
) => GetItemsFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
/// <summary>
/// Get people's roles from a show.
/// </summary>
/// <param name="showID">The ID of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
@ -372,7 +396,7 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="showSlug">The slug of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
@ -394,13 +418,12 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
/// <summary>
/// Get people's roles from a person.
/// </summary>
/// <param name="id">The id of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
@ -427,7 +450,7 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="slug">The slug of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
@ -449,13 +472,13 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default
) => GetRolesFromPeople(slug, where, new Sort<PeopleRole>(sort), limit);
/// <summary>
/// Setup relations between a show, a library and a collection
/// </summary>
/// <param name="showID">The show's ID to setup relations with</param>
/// <param name="libraryID">The library's ID to setup relations with (optional)</param>
/// <param name="collectionID">The collection's ID to setup relations with (optional)</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task AddShowLink(int showID, int? libraryID, int? collectionID);
/// <summary>
@ -464,19 +487,21 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="show">The show to setup relations with</param>
/// <param name="library">The library to setup relations with (optional)</param>
/// <param name="collection">The collection to setup relations with (optional)</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
/// <summary>
/// Get all resources with filters
/// </summary>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <typeparam name="T">The type of resources to load</typeparam>
/// <returns>A list of resources that match every filters</returns>
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default) where T : class, IResource;
Pagination limit = default)
where T : class, IResource;
/// <summary>
/// Get all resources with filters
@ -488,7 +513,8 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>A list of resources that match every filters</returns>
Task<ICollection<T>> GetAll<T>([Optional] Expression<Func<T, bool>> where,
Expression<Func<T, object>> sort,
Pagination limit = default) where T : class, IResource
Pagination limit = default)
where T : class, IResource
{
return GetAll(where, new Sort<T>(sort), limit);
}
@ -499,7 +525,8 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="where">A filter function</param>
/// <typeparam name="T">The type of resources to load</typeparam>
/// <returns>A list of resources that match every filters</returns>
Task<int> GetCount<T>(Expression<Func<T, bool>> where = null) where T : class, IResource;
Task<int> GetCount<T>(Expression<Func<T, bool>> where = null)
where T : class, IResource;
/// <summary>
/// Search for a resource
@ -507,15 +534,17 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="query">The search query</param>
/// <typeparam name="T">The type of resources</typeparam>
/// <returns>A list of 20 items that match the search query</returns>
Task<ICollection<T>> Search<T>(string query) where T : class, IResource;
Task<ICollection<T>> Search<T>(string query)
where T : class, IResource;
/// <summary>
/// Create a new resource.
/// </summary>
/// <param name="item">The item to register</param>
/// <typeparam name="T">The type of resource</typeparam>
/// <returns>The resource registers and completed by database's informations (related items & so on)</returns>
Task<T> Create<T>([NotNull] T item) where T : class, IResource;
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
Task<T> Create<T>([NotNull] T item)
where T : class, IResource;
/// <summary>
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
@ -523,17 +552,19 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="item">The item to register</param>
/// <typeparam name="T">The type of resource</typeparam>
/// <returns>The newly created item or the existing value if it existed.</returns>
Task<T> CreateIfNotExists<T>([NotNull] T item) where T : class, IResource;
Task<T> CreateIfNotExists<T>([NotNull] T item)
where T : class, IResource;
/// <summary>
/// Edit a resource
/// </summary>
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
/// <param name="item">The resource to edit, it's ID can't change.</param>
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
/// <typeparam name="T">The type of resources</typeparam>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
Task<T> Edit<T>(T item, bool resetOld) where T : class, IResource;
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
Task<T> Edit<T>(T item, bool resetOld)
where T : class, IResource;
/// <summary>
/// Delete a resource.
@ -541,7 +572,9 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="item">The resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
Task Delete<T>(T item) where T : class, IResource;
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete<T>(T item)
where T : class, IResource;
/// <summary>
/// Delete a resource by it's ID.
@ -549,7 +582,9 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="id">The id of the resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
Task Delete<T>(int id) where T : class, IResource;
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete<T>(int id)
where T : class, IResource;
/// <summary>
/// Delete a resource by it's slug.
@ -557,6 +592,8 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="slug">The slug of the resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
Task Delete<T>(string slug) where T : class, IResource;
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete<T>(string slug)
where T : class, IResource;
}
}

View File

@ -1,7 +1,25 @@
using Kyoo.Abstractions.Models;
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
namespace Kyoo.Abstractions.Controllers
{
@ -30,6 +48,7 @@ namespace Kyoo.Abstractions.Controllers
/// Merging metadata is the job of Kyoo, a complex <typeparamref name="T"/> is given
/// to make a precise search and give you every available properties, not to discard properties.
/// </remarks>
/// <typeparam name="T">The type of resource to retrieve metadata for.</typeparam>
/// <returns>A new <typeparamref name="T"/> containing metadata from your provider or null</returns>
[ItemCanBeNull]
Task<T> Get<T>([NotNull] T item)
@ -39,6 +58,7 @@ namespace Kyoo.Abstractions.Controllers
/// Search for a specific type of items with a given query.
/// </summary>
/// <param name="query">The search query to use.</param>
/// <typeparam name="T">The type of resource to search metadata for.</typeparam>
/// <returns>The list of items that could be found on this specific provider.</returns>
[ItemNotNull]
Task<ICollection<T>> Search<T>(string query)

View File

@ -0,0 +1,47 @@
// 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 <https://www.gnu.org/licenses/>.
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// A service to validate permissions.
/// </summary>
public interface IPermissionValidator
{
/// <summary>
/// Create an IAuthorizationFilter that will be used to validate permissions.
/// This can registered with any lifetime.
/// </summary>
/// <param name="attribute">The permission attribute to validate.</param>
/// <returns>An authorization filter used to validate the permission.</returns>
IFilterMetadata Create(PermissionAttribute attribute);
/// <summary>
/// Create an IAuthorizationFilter that will be used to validate permissions.
/// This can registered with any lifetime.
/// </summary>
/// <param name="attribute">
/// A partial attribute to validate. See <see cref="PartialPermissionAttribute"/>.
/// </param>
/// <returns>An authorization filter used to validate the permission.</returns>
IFilterMetadata Create(PartialPermissionAttribute attribute);
}
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Autofac;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Exceptions;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
@ -6,122 +24,15 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// Information about the pagination. How many items should be displayed and where to start.
/// </summary>
public readonly struct Pagination
{
/// <summary>
/// The count of items to return.
/// </summary>
public int Count { get; }
/// <summary>
/// Where to start? Using the given sort
/// </summary>
public int AfterID { get; }
/// <summary>
/// Create a new <see cref="Pagination"/> instance.
/// </summary>
/// <param name="count">Set the <see cref="Count"/> value</param>
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
public Pagination(int count, int afterID = 0)
{
Count = count;
AfterID = afterID;
}
/// <summary>
/// Implicitly create a new pagination from a limit number.
/// </summary>
/// <param name="limit">Set the <see cref="Count"/> value</param>
/// <returns>A new <see cref="Pagination"/> instance</returns>
public static implicit operator Pagination(int limit) => new(limit);
}
/// <summary>
/// Information about how a query should be sorted. What factor should decide the sort and in which order.
/// </summary>
/// <typeparam name="T">For witch type this sort applies</typeparam>
public readonly struct Sort<T>
{
/// <summary>
/// The sort key. This member will be used to sort the results.
/// </summary>
public Expression<Func<T, object>> Key { get; }
/// <summary>
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
/// </summary>
public bool Descendant { get; }
/// <summary>
/// Create a new <see cref="Sort{T}"/> instance.
/// </summary>
/// <param name="key">The sort key given. It is assigned to <see cref="Key"/>.</param>
/// <param name="descendant">Should this be in descendant order? The default is false.</param>
/// <exception cref="ArgumentException">If the given key is not a member.</exception>
public Sort(Expression<Func<T, object>> key, bool descendant = false)
{
Key = key;
Descendant = descendant;
if (!Utility.IsPropertyExpression(Key))
throw new ArgumentException("The given sort key is not valid.");
}
/// <summary>
/// Create a new <see cref="Sort{T}"/> instance from a key's name (case insensitive).
/// </summary>
/// <param name="sortBy">A key name with an optional order specifier. Format: "key:asc", "key:desc" or "key".</param>
/// <exception cref="ArgumentException">An invalid key or sort specifier as been given.</exception>
public Sort(string sortBy)
{
if (string.IsNullOrEmpty(sortBy))
{
Key = null;
Descendant = false;
return;
}
string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
ParameterExpression param = Expression.Parameter(typeof(T), "x");
MemberExpression property = Expression.Property(param, key);
Key = property.Type.IsValueType
? Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param)
: Expression.Lambda<Func<T, object>>(property, param);
Descendant = order switch
{
"desc" => true,
"asc" => false,
null => false,
_ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
};
}
}
/// <summary>
/// A base class for repositories. Every service implementing this will be handled by the <see cref="ILibraryManager"/>.
/// </summary>
public interface IBaseRepository
{
/// <summary>
/// The type for witch this repository is responsible or null if non applicable.
/// </summary>
Type RepositoryType { get; }
}
/// <summary>
/// A common repository for every resources.
/// </summary>
/// <typeparam name="T">The resource's type that this repository manage.</typeparam>
public interface IRepository<T> : IBaseRepository where T : class, IResource
public interface IRepository<T> : IBaseRepository
where T : class, IResource
{
/// <summary>
/// Get a resource from it's ID.
@ -131,6 +42,7 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>The resource found</returns>
[ItemNotNull]
Task<T> Get(int id);
/// <summary>
/// Get a resource from it's slug.
/// </summary>
@ -139,6 +51,7 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>The resource found</returns>
[ItemNotNull]
Task<T> Get(string slug);
/// <summary>
/// Get the first resource that match the predicate.
/// </summary>
@ -155,6 +68,7 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>The resource found</returns>
[ItemCanBeNull]
Task<T> GetOrDefault(int id);
/// <summary>
/// Get a resource from it's slug or null if it is not found.
/// </summary>
@ -162,6 +76,7 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>The resource found</returns>
[ItemCanBeNull]
Task<T> GetOrDefault(string slug);
/// <summary>
/// Get the first resource that match the predicate or null if it is not found.
/// </summary>
@ -189,6 +104,7 @@ namespace Kyoo.Abstractions.Controllers
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default);
/// <summary>
/// Get every resources that match all filters
/// </summary>
@ -209,12 +125,11 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>How many resources matched that filter</returns>
Task<int> GetCount(Expression<Func<T, bool>> where = null);
/// <summary>
/// Create a new resource.
/// </summary>
/// <param name="obj">The item to register</param>
/// <returns>The resource registers and completed by database's information (related items & so on)</returns>
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
[ItemNotNull]
Task<T> Create([NotNull] T obj);
@ -232,7 +147,7 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="edited">The resource to edit, it's ID can't change.</param>
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The resource edited and completed by database's information (related items & so on)</returns>
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
[ItemNotNull]
Task<T> Edit([NotNull] T edited, bool resetOld);
@ -241,18 +156,23 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="id">The ID of the resource</param>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete(int id);
/// <summary>
/// Delete a resource by it's slug
/// </summary>
/// <param name="slug">The slug of the resource</param>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete(string slug);
/// <summary>
/// Delete a resource
/// </summary>
/// <param name="obj">The resource to delete</param>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task Delete([NotNull] T obj);
/// <summary>
@ -260,9 +180,21 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task DeleteAll([NotNull] Expression<Func<T, bool>> where);
}
/// <summary>
/// A base class for repositories. Every service implementing this will be handled by the <see cref="ILibraryManager"/>.
/// </summary>
public interface IBaseRepository
{
/// <summary>
/// The type for witch this repository is responsible or null if non applicable.
/// </summary>
Type RepositoryType { get; }
}
/// <summary>
/// A repository to handle shows.
/// </summary>
@ -275,6 +207,7 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="showID">The ID of the show</param>
/// <param name="libraryID">The ID of the library (optional)</param>
/// <param name="collectionID">The ID of the collection (optional)</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task AddShowLink(int showID, int? libraryID, int? collectionID);
/// <summary>
@ -340,6 +273,7 @@ namespace Kyoo.Abstractions.Controllers
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The episode found</returns>
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
/// <summary>
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
/// </summary>
@ -358,6 +292,7 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="episodeNumber">The episode's number</param>
/// <returns>The episode found</returns>
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
/// <summary>
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
/// </summary>
@ -375,6 +310,7 @@ namespace Kyoo.Abstractions.Controllers
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
/// <returns>The episode found</returns>
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
/// <summary>
/// Get a episode from it's showID and it's absolute number.
/// </summary>
@ -405,13 +341,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="id">The ID of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
/// <summary>
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
@ -431,13 +368,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="slug">The slug of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
public Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
/// <summary>
/// Get items (A wrapper around shows or collections) from a library.
/// </summary>
@ -478,13 +416,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="showID">The ID of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetFromShow(int showID,
Expression<Func<PeopleRole, bool>> where = null,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a show.
/// </summary>
@ -504,13 +443,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="showSlug">The slug of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
Expression<Func<PeopleRole, bool>> where = null,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a show.
/// </summary>
@ -530,13 +470,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="id">The id of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetFromPeople(int id,
Expression<Func<PeopleRole, bool>> where = null,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a person.
/// </summary>
@ -556,13 +497,14 @@ namespace Kyoo.Abstractions.Controllers
/// </summary>
/// <param name="slug">The slug of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <returns>A list of items that match every filters</returns>
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
Expression<Func<PeopleRole, bool>> where = null,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a person.
/// </summary>
@ -587,7 +529,7 @@ namespace Kyoo.Abstractions.Controllers
/// Get a list of external ids that match all filters
/// </summary>
/// <param name="where">A predicate to add arbitrary filter</param>
/// <param name="sort">Sort information (sort order & sort by)</param>
/// <param name="sort">Sort information (sort order and sort by)</param>
/// <param name="limit">Pagination information (where to start and how many to get)</param>
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
/// <returns>A filtered list of external ids.</returns>
@ -602,11 +544,13 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="where">A predicate to add arbitrary filter</param>
/// <param name="sort">A sort by expression</param>
/// <param name="limit">Pagination information (where to start and how many to get)</param>
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
/// <returns>A filtered list of external ids.</returns>
Task<ICollection<MetadataID>> GetMetadataID<T>([Optional] Expression<Func<MetadataID, bool>> where,
Expression<Func<MetadataID, object>> sort,
Pagination limit = default
) where T : class, IMetadata
)
where T : class, IMetadata
=> GetMetadataID<T>(where, new Sort<MetadataID>(sort), limit);
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq;
@ -9,6 +27,43 @@ using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// A common interface that tasks should implement.
/// </summary>
public interface ITask
{
/// <summary>
/// The list of parameters
/// </summary>
/// <returns>
/// All parameters that this task as. Every one of them will be given to the run function with a value.
/// </returns>
public TaskParameters GetParameters();
/// <summary>
/// Start this task.
/// </summary>
/// <param name="arguments">
/// The list of parameters.
/// </param>
/// <param name="progress">
/// The progress reporter. Used to inform the sender the percentage of completion of this task
/// .</param>
/// <param name="cancellationToken">A token to request the task's cancellation.
/// If this task is not cancelled quickly, it might be killed by the runner.
/// </param>
/// <exception cref="TaskFailedException">
/// An exception meaning that the task has failed for handled reasons like invalid arguments,
/// invalid environment, missing plugins or failures not related to a default in the code.
/// This exception allow the task to display a failure message to the end user while others exceptions
/// will be displayed as unhandled exceptions and display a stack trace.
/// </exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public Task Run([NotNull] TaskParameters arguments,
[NotNull] IProgress<float> progress,
CancellationToken cancellationToken);
}
/// <summary>
/// A single task parameter. This struct contains metadata to display and utility functions to get them in the task.
/// </summary>
@ -43,7 +98,7 @@ namespace Kyoo.Abstractions.Controllers
/// <summary>
/// The value of the parameter.
/// </summary>
private object Value { get; init; }
private object _Value { get; init; }
/// <summary>
/// Create a new task parameter.
@ -93,7 +148,7 @@ namespace Kyoo.Abstractions.Controllers
{
Name = name,
Type = typeof(T),
Value = value
_Value = value
};
}
@ -104,7 +159,7 @@ namespace Kyoo.Abstractions.Controllers
/// <returns>A new parameter's value for this current parameter</returns>
public TaskParameter CreateValue(object value)
{
return this with {Value = value};
return this with { _Value = value };
}
/// <summary>
@ -115,9 +170,9 @@ namespace Kyoo.Abstractions.Controllers
public T As<T>()
{
if (typeof(T) == typeof(object))
return (T)Value;
return (T)_Value;
if (Value is IResource resource)
if (_Value is IResource resource)
{
if (typeof(T) == typeof(string))
return (T)(object)resource.Slug;
@ -125,7 +180,7 @@ namespace Kyoo.Abstractions.Controllers
return (T)(object)resource.ID;
}
return (T)Convert.ChangeType(Value, typeof(T));
return (T)Convert.ChangeType(_Value, typeof(T));
}
}
@ -140,14 +195,13 @@ namespace Kyoo.Abstractions.Controllers
/// <param name="name">The name of the task (case sensitive)</param>
public TaskParameter this[string name] => this.FirstOrDefault(x => x.Name == name);
/// <summary>
/// Create a new, empty, <see cref="TaskParameters"/>
/// </summary>
public TaskParameters() { }
/// <summary>
/// Create a <see cref="TaskParameters"/> with an initial parameters content
/// Create a <see cref="TaskParameters"/> with an initial parameters content.
/// </summary>
/// <param name="parameters">The list of parameters</param>
public TaskParameters(IEnumerable<TaskParameter> parameters)
@ -155,40 +209,4 @@ namespace Kyoo.Abstractions.Controllers
AddRange(parameters);
}
}
/// <summary>
/// A common interface that tasks should implement.
/// </summary>
public interface ITask
{
/// <summary>
/// The list of parameters
/// </summary>
/// <returns>
/// All parameters that this task as. Every one of them will be given to the run function with a value.
/// </returns>
public TaskParameters GetParameters();
/// <summary>
/// Start this task.
/// </summary>
/// <param name="arguments">
/// The list of parameters.
/// </param>
/// <param name="progress">
/// The progress reporter. Used to inform the sender the percentage of completion of this task
/// .</param>
/// <param name="cancellationToken">A token to request the task's cancellation.
/// If this task is not cancelled quickly, it might be killed by the runner.
/// </param>
/// <exception cref="TaskFailedException">
/// An exception meaning that the task has failed for handled reasons like invalid arguments,
/// invalid environment, missing plugins or failures not related to a default in the code.
/// This exception allow the task to display a failure message to the end user while others exceptions
/// will be displayed as unhandled exceptions and display a stack trace.
/// </exception>
public Task Run([NotNull] TaskParameters arguments,
[NotNull] IProgress<float> progress,
CancellationToken cancellationToken);
}
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

View File

@ -1,6 +1,24 @@
using Kyoo.Abstractions.Models;
// 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 <https://www.gnu.org/licenses/>.
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
namespace Kyoo.Abstractions.Controllers
{
@ -24,7 +42,6 @@ namespace Kyoo.Abstractions.Controllers
Task<bool> DownloadImages<T>([NotNull] T item, bool alwaysDownload = false)
where T : IThumbnails;
/// <summary>
/// Retrieve the local path of an image of the given item.
/// </summary>

View File

@ -0,0 +1,32 @@
// 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 <https://www.gnu.org/licenses/>.
using System.Threading.Tasks;
using Kyoo.Abstractions.Models;
namespace Kyoo.Abstractions.Controllers
{
public interface ITranscoder
{
Task<Track[]> ExtractInfos(Episode episode, bool reextract);
Task<string> Transmux(Episode episode);
Task<string> Transcode(Episode episode);
}
}

View File

@ -0,0 +1,269 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// A list of constant priorities used for <see cref="IStartupAction"/>'s <see cref="IStartupAction.Priority"/>.
/// It also contains helper methods for creating new <see cref="StartupAction"/>.
/// </summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name",
Justification = "StartupAction is nested and the name SA is short to improve readability in plugin's startup.")]
public static class SA
{
/// <summary>
/// The highest predefined priority existing for <see cref="StartupAction"/>.
/// </summary>
public const int Before = 5000;
/// <summary>
/// Items defining routing (see IApplicationBuilder.UseRouting use this priority.
/// </summary>
public const int Routing = 4000;
/// <summary>
/// Actions defining new static files router use this priority.
/// </summary>
public const int StaticFiles = 3000;
/// <summary>
/// Actions calling IApplicationBuilder.UseAuthentication use this priority.
/// </summary>
public const int Authentication = 2000;
/// <summary>
/// Actions calling IApplicationBuilder.UseAuthorization use this priority.
/// </summary>
public const int Authorization = 1000;
/// <summary>
/// Action adding endpoint should use this priority (with a negative modificator if there is a catchall).
/// </summary>
public const int Endpoint = 0;
/// <summary>
/// The lowest predefined priority existing for <see cref="StartupAction"/>.
/// It should run after all other actions.
/// </summary>
public const int After = -1000;
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction New(Action action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T> New<T>(Action<T> action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
=> new(action, priority);
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to run</param>
/// <param name="priority">The priority of the new action</param>
/// <typeparam name="T">A dependency that this action will use.</typeparam>
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
/// <returns>A new <see cref="StartupAction"/></returns>
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
=> new(action, priority);
/// <summary>
/// A <see cref="IStartupAction"/> with no dependencies.
/// </summary>
public class StartupAction : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke();
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with one dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
public class StartupAction<T> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(provider.GetRequiredService<T>());
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with two dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
/// <typeparam name="T2">The second dependency to use.</typeparam>
public class StartupAction<T, T2> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T, T2> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T, T2}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T, T2> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(
provider.GetRequiredService<T>(),
provider.GetRequiredService<T2>()
);
}
}
/// <summary>
/// A <see cref="IStartupAction"/> with three dependencies.
/// </summary>
/// <typeparam name="T">The dependency to use.</typeparam>
/// <typeparam name="T2">The second dependency to use.</typeparam>
/// <typeparam name="T3">The third dependency to use.</typeparam>
public class StartupAction<T, T2, T3> : IStartupAction
{
/// <summary>
/// The action to execute at startup.
/// </summary>
private readonly Action<T, T2, T3> _action;
/// <inheritdoc />
public int Priority { get; }
/// <summary>
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
/// </summary>
/// <param name="action">The action to execute on startup.</param>
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
public StartupAction(Action<T, T2, T3> action, int priority)
{
_action = action;
Priority = priority;
}
/// <inheritdoc />
public void Run(IServiceProvider provider)
{
_action.Invoke(
provider.GetRequiredService<T>(),
provider.GetRequiredService<T2>(),
provider.GetRequiredService<T3>()
);
}
}
}
/// <summary>
/// An action executed on kyoo's startup to initialize the asp-net container.
/// </summary>
/// <remarks>
/// This is the base interface, see <see cref="SA.StartupAction"/> for a simpler use of this.
/// </remarks>
public interface IStartupAction
{
/// <summary>
/// The priority of this action. The actions will be executed on descending priority order.
/// If two actions have the same priority, their order is undefined.
/// </summary>
int Priority { get; }
/// <summary>
/// Run this action to configure the container, a service provider containing all services can be used.
/// </summary>
/// <param name="provider">The service provider containing all services can be used.</param>
void Run(IServiceProvider provider);
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>

View File

@ -0,0 +1,28 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ComputedAttribute : NotMergeableAttribute { }
}

View File

@ -0,0 +1,29 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using Kyoo.Abstractions.Controllers;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// The targeted relation can be edited via calls to the repository's <see cref="IRepository{T}.Edit"/> method.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class EditableRelationAttribute : Attribute { }
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
@ -27,7 +45,6 @@ namespace Kyoo.Abstractions.Models.Attributes
/// </summary>
public bool StripScheme { get; set; }
/// <summary>
/// Create a new <see cref="FileSystemMetadataAttribute"/> using the specified schemes.
/// </summary>

View File

@ -1,14 +1,26 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using Kyoo.Abstractions.Controllers;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// The targeted relation can be edited via calls to the repository's <see cref="IRepository{T}.Edit"/> method.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class EditableRelationAttribute : Attribute { }
/// <summary>
/// The targeted relation can be loaded via a call to <see cref="ILibraryManager.Load"/>.
/// </summary>

View File

@ -0,0 +1,40 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// Specify that a property can't be merged.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NotMergeableAttribute : Attribute { }
/// <summary>
/// An interface with a method called when this object is merged.
/// </summary>
public interface IOnMerge
{
/// <summary>
/// This function is called after the object has been merged.
/// </summary>
/// <param name="merged">The object that has been merged with this.</param>
void OnMerge(object merged);
}
}

View File

@ -0,0 +1,88 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using Kyoo.Abstractions.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Abstractions.Models.Permissions
{
/// <summary>
/// Specify one part of a permissions needed for the API (the kind or the type).
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PartialPermissionAttribute : Attribute, IFilterFactory
{
/// <summary>
/// The needed permission type.
/// </summary>
public string Type { get; }
/// <summary>
/// The needed permission kind.
/// </summary>
public Kind Kind { get; }
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <remarks>
/// With this attribute, you can only specify a type or a kind.
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
/// lead to unspecified behaviors.
/// </remarks>
/// <param name="type">
/// The type of the action
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
/// </param>
public PartialPermissionAttribute(string type)
{
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
type = type[..^3];
Type = type.ToLower();
}
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <remarks>
/// With this attribute, you can only specify a type or a kind.
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
/// lead to unspecified behaviors.
/// </remarks>
/// <param name="permission">The kind of permission needed.</param>
public PartialPermissionAttribute(Kind permission)
{
Kind = permission;
}
/// <inheritdoc />
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
}
/// <inheritdoc />
public bool IsReusable => true;
}
}

View File

@ -0,0 +1,128 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using Kyoo.Abstractions.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Abstractions.Models.Permissions
{
/// <summary>
/// The kind of permission needed.
/// </summary>
public enum Kind
{
/// <summary>
/// Allow the user to read for this kind of data.
/// </summary>
Read,
/// <summary>
/// Allow the user to write for this kind of data.
/// </summary>
Write,
/// <summary>
/// Allow the user to create this kind of data.
/// </summary>
Create,
/// <summary>
/// Allow the user to delete this kind od data.
/// </summary>
Delete
}
/// <summary>
/// The group of the permission.
/// </summary>
public enum Group
{
/// <summary>
/// Allow all operations on basic items types.
/// </summary>
Overall,
/// <summary>
/// Allow operation on sensitive items like libraries path, configurations and so on.
/// </summary>
Admin
}
/// <summary>
/// Specify permissions needed for the API.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : Attribute, IFilterFactory
{
/// <summary>
/// The needed permission as string.
/// </summary>
public string Type { get; }
/// <summary>
/// The needed permission kind.
/// </summary>
public Kind Kind { get; }
/// <summary>
/// The group of this permission.
/// </summary>
public Group Group { get; }
/// <summary>
/// Ask a permission to run an action.
/// </summary>
/// <param name="type">
/// The type of the action
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
/// </param>
/// <param name="permission">The kind of permission needed.</param>
/// <param name="group">
/// The group of this permission (allow grouped permission like overall.read
/// for all read permissions of this group).
/// </param>
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;
}
/// <inheritdoc />
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
}
/// <inheritdoc />
public bool IsReusable => true;
/// <summary>
/// Return this permission attribute as a string.
/// </summary>
/// <returns>The string representation.</returns>
public string AsPermissionString()
{
return Type;
}
}
}

View File

@ -0,0 +1,28 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// Remove a property from the deserialization pipeline. The user can't input value for this property.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class DeserializeIgnoreAttribute : Attribute { }
}

View File

@ -1,19 +1,25 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// Remove an property from the serialization pipeline. It will simply be skipped.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class SerializeIgnoreAttribute : Attribute {}
/// <summary>
/// Remove a property from the deserialization pipeline. The user can't input value for this property.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class DeserializeIgnoreAttribute : Attribute {}
/// <summary>
/// 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.

View File

@ -0,0 +1,28 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
namespace Kyoo.Abstractions.Models.Attributes
{
/// <summary>
/// Remove an property from the serialization pipeline. It will simply be skipped.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class SerializeIgnoreAttribute : Attribute { }
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
@ -43,7 +61,6 @@ namespace Kyoo.Abstractions.Models.Attributes
/// </summary>
public bool IsHidden { get; set; }
/// <summary>
/// Create a new <see cref="TaskMetadataAttribute"/> with the given slug, name and description.
/// </summary>

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Models
{
/// <summary>
@ -11,7 +29,7 @@ namespace Kyoo.Abstractions.Models
public float StartTime { get; set; }
/// <summary>
/// The end time of the chapter (in second from the start of the episode)&.
/// The end time of the chapter (in second from the start of the episode).
/// </summary>
public float EndTime { get; set; }

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Reflection;
@ -21,7 +39,6 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public Type Type { get; }
/// <summary>
/// Create a new <see cref="ConfigurationReference"/> using a given path and type.
/// This method does not create sub configuration resources. Please see <see cref="CreateReference"/>
@ -53,7 +70,6 @@ namespace Kyoo.Abstractions.Models
new ConfigurationReference(path, type)
};
if (!type.IsClass || type.AssemblyQualifiedName?.StartsWith("System") == true)
return ret;
@ -89,7 +105,6 @@ namespace Kyoo.Abstractions.Models
return CreateReference(path, typeof(T));
}
public static ConfigurationReference CreateUntyped(string path)
{
return new(path, null);

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Runtime.Serialization;
@ -25,7 +43,7 @@ namespace Kyoo.Abstractions.Models.Exceptions
{ }
/// <summary>
/// The serialization constructor
/// The serialization constructor.
/// </summary>
/// <param name="info">Serialization infos</param>
/// <param name="context">The serialization context</param>

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Runtime.Serialization;
using Kyoo.Abstractions.Controllers;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Runtime.Serialization;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Runtime.Serialization;
using Kyoo.Abstractions.Controllers;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
@ -10,8 +28,19 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public enum ItemType
{
/// <summary>
/// The <see cref="LibraryItem"/> is a <see cref="Show"/>.
/// </summary>
Show,
/// <summary>
/// The <see cref="LibraryItem"/> is a Movie (a <see cref="Show"/> with <see cref="Models.Show.IsMovie"/> equals to true).
/// </summary>
Movie,
/// <summary>
/// The <see cref="LibraryItem"/> is a <see cref="Collection"/>.
/// </summary>
Collection
}
@ -70,7 +99,6 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public ItemType Type { get; set; }
/// <summary>
/// Create a new, empty <see cref="LibraryItem"/>.
/// </summary>

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Linq.Expressions;
using Kyoo.Abstractions.Models.Attributes;
@ -9,6 +27,14 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public class MetadataID
{
/// <summary>
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
/// </summary>
public static Expression<Func<MetadataID, object>> PrimaryKey
{
get { return x => new { First = x.ResourceID, Second = x.ProviderID }; }
}
/// <summary>
/// The ID of the resource which possess the metadata.
/// </summary>
@ -33,13 +59,5 @@ namespace Kyoo.Abstractions.Models
/// The URL of the resource on the external provider.
/// </summary>
public string Link { get; set; }
/// <summary>
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
/// </summary>
public static Expression<Func<MetadataID, object>> PrimaryKey
{
get { return x => new { First = x.ResourceID, Second = x.ProviderID }; }
}
}
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq;
@ -9,7 +27,8 @@ namespace Kyoo.Abstractions.Models
/// A page of resource that contains information about the pagination of resources.
/// </summary>
/// <typeparam name="T">The type of resource contained in this page.</typeparam>
public class Page<T> where T : IResource
public class Page<T>
where T : IResource
{
/// <summary>
/// The link of the current page.
@ -36,7 +55,6 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public ICollection<T> Items { get; }
/// <summary>
/// Create a new <see cref="Page{T}"/>.
/// </summary>

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Models
{
/// <summary>
@ -26,6 +44,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the People playing the role.
/// </summary>
public int PeopleID { get; set; }
/// <summary>
/// The people that played this role.
/// </summary>
@ -35,6 +54,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the Show where the People playing in.
/// </summary>
public int ShowID { get; set; }
/// <summary>
/// The show where the People played in.
/// </summary>

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
@ -26,6 +44,7 @@ namespace Kyoo.Abstractions.Models
? GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber)
: null;
}
[UsedImplicitly] [NotNull] private set
{
if (value == null)
@ -64,6 +83,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the Show containing this episode.
/// </summary>
[SerializeIgnore] public int ShowID { get; set; }
/// <summary>
/// The show that contains this episode. This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
/// </summary>
@ -73,6 +93,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the Season containing this episode.
/// </summary>
[SerializeIgnore] public int? SeasonID { get; set; }
/// <summary>
/// The season that contains this episode.
/// This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
@ -138,7 +159,6 @@ namespace Kyoo.Abstractions.Models
/// </summary>
[EditableRelation] [LoadableRelation] public ICollection<Track> Tracks { get; set; }
/// <summary>
/// Get the slug of an episode.
/// </summary>

View File

@ -1,4 +1,22 @@
using System.Collections.Generic;
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq;
@ -14,7 +32,8 @@ namespace Kyoo.Abstractions.Models
/// <summary>
/// The link to metadata providers that this show has. See <see cref="MetadataID"/> for more information.
/// </summary>
[EditableRelation] [LoadableRelation]
[EditableRelation]
[LoadableRelation]
public ICollection<MetadataID> ExternalIDs { get; set; }
}

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using Kyoo.Abstractions.Controllers;
namespace Kyoo.Abstractions.Models

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using Kyoo.Abstractions.Controllers;

View File

@ -1,4 +1,22 @@
using System.Collections.Generic;
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;
namespace Kyoo.Abstractions.Models

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Controllers;

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
@ -24,9 +42,10 @@ namespace Kyoo.Abstractions.Models
return $"{ShowID}-s{SeasonNumber}";
return $"{ShowSlug ?? Show?.Slug}-s{SeasonNumber}";
}
[UsedImplicitly] [NotNull] private set
{
Match match = Regex.Match(value ?? "", @"(?<show>.+)-s(?<season>\d+)");
Match match = Regex.Match(value ?? string.Empty, @"(?<show>.+)-s(?<season>\d+)");
if (!match.Success)
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
@ -44,6 +63,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the Show containing this season.
/// </summary>
[SerializeIgnore] public int ShowID { get; set; }
/// <summary>
/// The show that contains this season.
/// This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
@ -103,6 +121,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the Studio that made this show.
/// </summary>
[SerializeIgnore] public int? StudioID { get; set; }
/// <summary>
/// The Studio that made this show.
/// This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
@ -145,19 +164,48 @@ namespace Kyoo.Abstractions.Models
public void OnMerge(object merged)
{
if (People != null)
{
foreach (PeopleRole link in People)
link.Show = this;
}
if (Seasons != null)
{
foreach (Season season in Seasons)
season.Show = this;
}
if (Episodes != null)
{
foreach (Episode episode in Episodes)
episode.Show = this;
}
}
}
/// <summary>
/// The enum containing show's status.
/// </summary>
public enum Status { Unknown, Finished, Airing, Planned }
public enum Status
{
/// <summary>
/// The status of the show is not known.
/// </summary>
Unknown,
/// <summary>
/// The show has finished airing.
/// </summary>
Finished,
/// <summary>
/// The show is still actively airing.
/// </summary>
Airing,
/// <summary>
/// This show has not aired yet but has been announced.
/// </summary>
Planned
}
}

View File

@ -1,4 +1,22 @@
using System.Collections.Generic;
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
@ -13,10 +31,30 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public enum StreamType
{
/// <summary>
/// The type of the stream is not known.
/// </summary>
Unknown = 0,
/// <summary>
/// The stream is a video.
/// </summary>
Video = 1,
/// <summary>
/// The stream is an audio.
/// </summary>
Audio = 2,
/// <summary>
/// The stream is a subtitle.
/// </summary>
Subtitle = 3,
/// <summary>
/// The stream is an attachement (a font, an image or something else).
/// Only fonts are handled by kyoo but they are not saved to the database.
/// </summary>
Attachment = 4
}
@ -36,8 +74,9 @@ namespace Kyoo.Abstractions.Models
string type = Type.ToString().ToLower();
string index = TrackIndex != 0 ? $"-{TrackIndex}" : string.Empty;
string episode = EpisodeSlug ?? Episode?.Slug ?? EpisodeID.ToString();
return $"{episode}.{Language ?? "und"}{index}{(IsForced ? ".forced" : "")}.{type}";
return $"{episode}.{Language ?? "und"}{index}{(IsForced ? ".forced" : string.Empty)}.{type}";
}
[UsedImplicitly] private set
{
if (value == null)
@ -46,8 +85,10 @@ namespace Kyoo.Abstractions.Models
@"(?<ep>[^\.]+)\.(?<lang>\w{0,3})(-(?<index>\d+))?(\.(?<forced>forced))?\.(?<type>\w+)(\.\w*)?");
if (!match.Success)
{
throw new ArgumentException("Invalid track slug. " +
"Format: {episodeSlug}.{language}[-{index}][.forced].{type}[.{extension}]");
}
EpisodeSlug = match.Groups["ep"].Value;
Language = match.Groups["lang"].Value;
@ -79,7 +120,6 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public string Codec { get; set; }
/// <summary>
/// Is this stream the default one of it's type?
/// </summary>
@ -109,6 +149,7 @@ namespace Kyoo.Abstractions.Models
/// The ID of the episode that uses this track.
/// </summary>
[SerializeIgnore] public int EpisodeID { get; set; }
/// <summary>
/// The episode that uses this track.
/// </summary>
@ -126,7 +167,7 @@ namespace Kyoo.Abstractions.Models
{
get
{
string language = GetLanguage(Language);
string language = _GetLanguage(Language);
if (language == null)
return $"Unknown (index: {TrackIndex})";
@ -144,7 +185,7 @@ namespace Kyoo.Abstractions.Models
}
// Converting mkv track language to c# system language tag.
private static string GetLanguage(string mkvLanguage)
private static string _GetLanguage(string mkvLanguage)
{
// TODO delete this and have a real way to get the language string from the ISO-639-2.
return mkvLanguage switch
@ -160,9 +201,8 @@ namespace Kyoo.Abstractions.Models
/// </summary>
/// <param name="baseSlug">The slug to edit</param>
/// <param name="type">The new type of this </param>
/// <returns></returns>
public static string BuildSlug(string baseSlug,
StreamType type)
/// <returns>The completed slug.</returns>
public static string BuildSlug(string baseSlug, StreamType type)
{
return baseSlug.EndsWith($".{type}", StringComparison.InvariantCultureIgnoreCase)
? baseSlug

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
namespace Kyoo.Abstractions.Models
@ -51,30 +69,4 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public ICollection<WatchedEpisode> CurrentlyWatching { get; set; }
}
/// <summary>
/// Metadata of episode currently watching by an user
/// </summary>
public class WatchedEpisode
{
/// <summary>
/// The ID of the user that started watching this episode.
/// </summary>
public int UserID { get; set; }
/// <summary>
/// The ID of the episode started.
/// </summary>
public int EpisodeID { get; set; }
/// <summary>
/// The <see cref="Episode"/> started.
/// </summary>
public Episode Episode { get; set; }
/// <summary>
/// Where the player has stopped watching the episode (between 0 and 100).
/// </summary>
public int WatchedPercentage { get; set; }
}
}

View File

@ -0,0 +1,46 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Models
{
/// <summary>
/// Metadata of episode currently watching by an user
/// </summary>
public class WatchedEpisode
{
/// <summary>
/// The ID of the user that started watching this episode.
/// </summary>
public int UserID { get; set; }
/// <summary>
/// The ID of the episode started.
/// </summary>
public int EpisodeID { get; set; }
/// <summary>
/// The <see cref="Episode"/> started.
/// </summary>
public Episode Episode { get; set; }
/// <summary>
/// Where the player has stopped watching the episode (between 0 and 100).
/// </summary>
public int WatchedPercentage { get; set; }
}
}

View File

@ -1,4 +1,22 @@
using System.Collections.Generic;
// 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 <https://www.gnu.org/licenses/>.
using System.Collections.Generic;
namespace Kyoo.Abstractions.Models
{

View File

@ -0,0 +1,35 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Models
{
/// <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; }
}
}

View File

@ -0,0 +1,54 @@
// 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 <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// Information about the pagination. How many items should be displayed and where to start.
/// </summary>
public readonly struct Pagination
{
/// <summary>
/// The count of items to return.
/// </summary>
public int Count { get; }
/// <summary>
/// Where to start? Using the given sort.
/// </summary>
public int AfterID { get; }
/// <summary>
/// Create a new <see cref="Pagination"/> instance.
/// </summary>
/// <param name="count">Set the <see cref="Count"/> value</param>
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
public Pagination(int count, int afterID = 0)
{
Count = count;
AfterID = afterID;
}
/// <summary>
/// Implicitly create a new pagination from a limit number.
/// </summary>
/// <param name="limit">Set the <see cref="Count"/> value</param>
/// <returns>A new <see cref="Pagination"/> instance</returns>
public static implicit operator Pagination(int limit) => new(limit);
}
}

View File

@ -0,0 +1,88 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Linq.Expressions;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// Information about how a query should be sorted. What factor should decide the sort and in which order.
/// </summary>
/// <typeparam name="T">For witch type this sort applies</typeparam>
public readonly struct Sort<T>
{
/// <summary>
/// The sort key. This member will be used to sort the results.
/// </summary>
public Expression<Func<T, object>> Key { get; }
/// <summary>
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
/// </summary>
public bool Descendant { get; }
/// <summary>
/// Create a new <see cref="Sort{T}"/> instance.
/// </summary>
/// <param name="key">The sort key given. It is assigned to <see cref="Key"/>.</param>
/// <param name="descendant">Should this be in descendant order? The default is false.</param>
/// <exception cref="ArgumentException">If the given key is not a member.</exception>
public Sort(Expression<Func<T, object>> key, bool descendant = false)
{
Key = key;
Descendant = descendant;
if (!Utility.IsPropertyExpression(Key))
throw new ArgumentException("The given sort key is not valid.");
}
/// <summary>
/// Create a new <see cref="Sort{T}"/> instance from a key's name (case insensitive).
/// </summary>
/// <param name="sortBy">A key name with an optional order specifier. Format: "key:asc", "key:desc" or "key".</param>
/// <exception cref="ArgumentException">An invalid key or sort specifier as been given.</exception>
public Sort(string sortBy)
{
if (string.IsNullOrEmpty(sortBy))
{
Key = null;
Descendant = false;
return;
}
string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
ParameterExpression param = Expression.Parameter(typeof(T), "x");
MemberExpression property = Expression.Property(param, key);
Key = property.Type.IsValueType
? Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param)
: Expression.Lambda<Func<T, object>>(property, param);
Descendant = order switch
{
"desc" => true,
"asc" => false,
null => false,
_ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
};
}
}
}

View File

@ -1,4 +1,22 @@
using System;
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -130,13 +148,12 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public ICollection<Chapter> Chapters { get; set; }
/// <summary>
/// Create a <see cref="WatchItem"/> from an <see cref="Episode"/>.
/// </summary>
/// <param name="ep">The episode to transform.</param>
/// <param name="library">
/// A library manager to retrieve the next and previous episode and load the show & tracks of the episode.
/// A library manager to retrieve the next and previous episode and load the show and tracks of the episode.
/// </param>
/// <returns>A new WatchItem representing the given episode.</returns>
public static async Task<WatchItem> FromEpisode(Episode ep, ILibraryManager library)
@ -191,13 +208,13 @@ namespace Kyoo.Abstractions.Models
Subtitles = ep.Tracks.Where(x => x.Type == StreamType.Subtitle).ToArray(),
PreviousEpisode = previous,
NextEpisode = next,
Chapters = await GetChapters(ep.Path)
Chapters = await _GetChapters(ep.Path)
};
}
// TODO move this method in a controller to support abstraction.
// TODO use a IFileManager to retrieve and read files.
private static async Task<ICollection<Chapter>> GetChapters(string episodePath)
private static async Task<ICollection<Chapter>> _GetChapters(string episodePath)
{
string path = PathIO.Combine(
PathIO.GetDirectoryName(episodePath)!,

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using Autofac;
using Autofac.Builder;
using Kyoo.Abstractions.Controllers;

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections;
using System.Collections.Generic;
@ -16,7 +34,7 @@ namespace Kyoo.Utils
/// </summary>
/// <param name="self">The IEnumerable to map. If self is null, an empty list is returned</param>
/// <param name="mapper">The function that will map each items</param>
/// <typeparam name="T">The type of items in <see cref="self"/></typeparam>
/// <typeparam name="T">The type of items in <paramref name="self"/></typeparam>
/// <typeparam name="T2">The type of items in the returned list</typeparam>
/// <returns>The list mapped.</returns>
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
@ -48,11 +66,11 @@ namespace Kyoo.Utils
/// Note: <see cref="SelectAsync{T,T2}"/> might interest you.
/// </summary>
/// <param name="self">The IEnumerable to map.</param>
/// <param name="mapper">The asynchronous function that will map each items</param>
/// <typeparam name="T">The type of items in <see cref="self"/></typeparam>
/// <typeparam name="T2">The type of items in the returned list</typeparam>
/// <returns>The list mapped as an AsyncEnumerable</returns>
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
/// <param name="mapper">The asynchronous function that will map each items.</param>
/// <typeparam name="T">The type of items in <paramref name="self"/>.</typeparam>
/// <typeparam name="T2">The type of items in the returned list.</typeparam>
/// <returns>The list mapped as an AsyncEnumerable.</returns>
/// <exception cref="ArgumentNullException">The list or the mapper can't be null.</exception>
[LinqTunnel]
public static IAsyncEnumerable<T2> MapAsync<T, T2>([NotNull] this IEnumerable<T> self,
[NotNull] Func<T, int, Task<T2>> mapper)
@ -82,7 +100,7 @@ namespace Kyoo.Utils
/// </summary>
/// <param name="self">The IEnumerable to map</param>
/// <param name="mapper">The asynchronous function that will map each items</param>
/// <typeparam name="T">The type of items in <see cref="self"/></typeparam>
/// <typeparam name="T">The type of items in <paramref name="self"/></typeparam>
/// <typeparam name="T2">The type of items in the returned list</typeparam>
/// <returns>The list mapped as an AsyncEnumerable</returns>
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
@ -198,6 +216,7 @@ namespace Kyoo.Utils
/// </summary>
/// <param name="self">The list to enumerate. If this is null, the function result in a no-op</param>
/// <param name="action">The action to execute for each arguments</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task ForEachAsync([CanBeNull] this IEnumerable self, Func<object, Task> action)
{
if (self == null)
@ -212,6 +231,7 @@ namespace Kyoo.Utils
/// <param name="self">The list to enumerate. If this is null, the function result in a no-op</param>
/// <param name="action">The asynchronous action to execute for each arguments</param>
/// <typeparam name="T">The type of items in the list.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task ForEachAsync<T>([CanBeNull] this IEnumerable<T> self, Func<T, Task> action)
{
if (self == null)
@ -226,6 +246,7 @@ namespace Kyoo.Utils
/// <param name="self">The async list to enumerate. If this is null, the function result in a no-op</param>
/// <param name="action">The action to execute for each arguments</param>
/// <typeparam name="T">The type of items in the list.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task ForEachAsync<T>([CanBeNull] this IAsyncEnumerable<T> self, Action<T> action)
{
if (self == null)

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Collections;
using System.Collections.Generic;
@ -21,6 +39,7 @@ namespace Kyoo.Utils
/// <param name="first">The first enumerable to merge</param>
/// <param name="second">The second enumerable to merge, if items from this list are equals to one from the first, they are not kept</param>
/// <param name="isEqual">Equality function to compare items. If this is null, duplicated elements are kept</param>
/// <typeparam name="T">The type of items in the lists to merge.</typeparam>
/// <returns>The two list merged as an array</returns>
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
public static T[] MergeLists<T>([CanBeNull] IEnumerable<T> first,
@ -145,7 +164,7 @@ namespace Kyoo.Utils
/// <param name="first">The object to assign</param>
/// <param name="second">The object containing new values</param>
/// <typeparam name="T">Fields of T will be used</typeparam>
/// <returns><see cref="first"/></returns>
/// <returns><paramref name="first"/></returns>
public static T Assign<T>(T first, T second)
{
Type type = typeof(T);
@ -188,7 +207,7 @@ namespace Kyoo.Utils
/// Filter fields that will be merged
/// </param>
/// <typeparam name="T">Fields of T will be completed</typeparam>
/// <returns><see cref="first"/></returns>
/// <returns><paramref name="first"/></returns>
/// <exception cref="ArgumentNullException">If first is null</exception>
public static T Complete<T>([NotNull] T first,
[CanBeNull] T second,
@ -219,7 +238,8 @@ namespace Kyoo.Utils
{
Type[] dictionaryTypes = Utility.GetGenericDefinition(property.PropertyType, typeof(IDictionary<,>))
.GenericTypeArguments;
object[] parameters = {
object[] parameters =
{
property.GetValue(first),
value,
false
@ -242,7 +262,7 @@ namespace Kyoo.Utils
}
/// <summary>
/// This will set missing values of <see cref="first"/> to the corresponding values of <see cref="second"/>.
/// This will set missing values of <paramref name="first"/> to the corresponding values of <paramref name="second"/>.
/// Enumerable will be merged (concatenated) and Dictionaries too.
/// At the end, the OnMerge method of first will be called if first is a <see cref="IOnMerge"/>.
/// </summary>
@ -259,7 +279,7 @@ namespace Kyoo.Utils
/// Filter fields that will be merged
/// </param>
/// <typeparam name="T">Fields of T will be merged</typeparam>
/// <returns><see cref="first"/></returns>
/// <returns><paramref name="first"/></returns>
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
public static T Merge<T>([CanBeNull] T first,
[CanBeNull] T second,
@ -290,7 +310,8 @@ namespace Kyoo.Utils
{
Type[] dictionaryTypes = Utility.GetGenericDefinition(property.PropertyType, typeof(IDictionary<,>))
.GenericTypeArguments;
object[] parameters = {
object[] parameters =
{
oldValue,
newValue,
false
@ -326,11 +347,11 @@ namespace Kyoo.Utils
}
/// <summary>
/// Set every fields of <see cref="obj"/> to the default value.
/// Set every fields of <paramref name="obj"/> to the default value.
/// </summary>
/// <param name="obj">The object to nullify</param>
/// <typeparam name="T">Fields of T will be nullified</typeparam>
/// <returns><see cref="obj"/></returns>
/// <returns><paramref name="obj"/></returns>
public static T Nullify<T>(T obj)
{
Type type = typeof(T);

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Reflection;
@ -22,6 +40,7 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the action.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T>(Action<T> action)
{
@ -32,6 +51,8 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the action.</typeparam>
/// <typeparam name="T2">The second parameter of the action.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2>(Action<T, T2> action)
{
@ -42,6 +63,9 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the action.</typeparam>
/// <typeparam name="T2">The second parameter of the action.</typeparam>
/// <typeparam name="T3">The third parameter of the action.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3>(Action<T, T2, T3> action)
{
@ -52,6 +76,7 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The return type of function.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T>(Func<T> action)
{
@ -62,6 +87,8 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the function.</typeparam>
/// <typeparam name="T2">The return type of function.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2>(Func<T, T2> action)
{
@ -72,6 +99,9 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the function.</typeparam>
/// <typeparam name="T2">The second parameter of the function.</typeparam>
/// <typeparam name="T3">The return type of function.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3>(Func<T, T2, T3> action)
{
@ -82,6 +112,10 @@ namespace Kyoo.Utils
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <typeparam name="T">The first parameter of the function.</typeparam>
/// <typeparam name="T2">The second parameter of the function.</typeparam>
/// <typeparam name="T3">The third parameter of the function.</typeparam>
/// <typeparam name="T4">The return type of function.</typeparam>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3, T4>(Func<T, T2, T3, T4> action)
{

View File

@ -1,3 +1,21 @@
// 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 <https://www.gnu.org/licenses/>.
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -18,7 +36,6 @@ namespace Kyoo.Utils
/// </param>
/// <typeparam name="T">The type of the item in the task.</typeparam>
/// <returns>A continuation task wrapping the initial task and adding a continuation method.</returns>
/// <exception cref="TaskCanceledException"></exception>
/// <exception cref="TaskCanceledException">The source task has been canceled.</exception>
public static Task<T> Then<T>(this Task<T> task, Action<T> then)
{

Some files were not shown because too many files have changed in this diff Show More