Merge pull request #36 from AnonymusRaccoon/windows

Supporting windows
This commit is contained in:
Zoe Roux 2021-09-02 14:20:21 +02:00 committed by GitHub
commit 81e0d09135
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
130 changed files with 1100 additions and 425 deletions

View File

@ -1,5 +1,5 @@
name: Analysis
on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]
jobs:
analysis:

View File

@ -1,5 +1,5 @@
name: Build
on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]
jobs:
build:
@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-latest #ubuntu-16.04 # We are using an old version of ubuntu to have an old libc version (forward compatibility exist but not backward)
- os: ubuntu-latest
runtime: linux-x64
artifact: linux
- os: windows-latest
@ -35,13 +35,18 @@ jobs:
elif [[ "${{runner.os}}" == "macOS" ]]; then
brew install ffmpeg
else
# sudo add-apt-repository -y "deb http://azure.archive.ubuntu.com/ubuntu groovy main multiverse restricted universe"
sudo apt-get update
sudo apt-get update
sudo apt-get install -y libavutil-dev libavcodec-dev libavformat-dev
fi
- name: Enabling windows compilations tools
if: matrix.artifact == 'windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Select the project to build
shell: bash
run: |
echo "PROJECT=$([ "${{runner.os}}" == "Windows" ] \
&& echo " -p:IncludeConsole=true Kyoo.Host.WindowsTrait" \
|| echo Kyoo.Host.Console)" >> $GITHUB_ENV
- name: Build the app
env:
INCLUDE: ${{env.INCLUDE}};C:\Program Files\FFmpeg\include
@ -49,7 +54,7 @@ jobs:
LIBPATH: ${{env.LIBPATH}};C:\Program Files\FFmpeg\lib
CFLAGS: -I/usr/local/include
LDFLAGS: -L/usr/local/lib
run: dotnet publish -r ${{matrix.runtime}} -c Release -o dist Kyoo
run: dotnet publish -r ${{matrix.runtime}} -c Release -o dist ${{env.PROJECT}}
- name: Compression output
shell: bash
run: |
@ -69,7 +74,34 @@ jobs:
path: |
*.zip
*.tar.gz
windows_release:
name: Create windows release
runs-on: windows-latest
needs: build
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v1
- name: Download windows build
uses: actions/download-artifact@v2
with:
name: kyoo_windows
path: artifact
- name: Unzip windows files
run: mkdir dist_win && 7z x artifact/kyoo_windows.zip -odist_win
- name: Install Inno Setup
shell: cmd
run: |
curl -L https://jrsoftware.org/download.php/is.exe > innosetup.exe
innosetup.exe /VERYSILENT /SUPPRESSMSGBOXES /Log=log.txt || (cat log.txt && exit 1)
- name: Create windows installer
shell: bash
run: iscc -Dkyoo=$(realpath dist_win) -O./ -Fkyoo-windows deployment/kyoo-windows.iss
- uses: actions/upload-artifact@v2
with:
name: kyoo_windows_installer
path: ./kyoo-windows.exe
release:
name: Create debian, rpm & arch releases
runs-on: ubuntu-latest
@ -80,7 +112,8 @@ jobs:
version: v0.0.1 #${{ github.ref }}
steps:
- uses: actions/checkout@v1
- uses: actions/download-artifact@v2
- name: Download linux build
uses: actions/download-artifact@v2
with:
name: kyoo_linux
path: artifact
@ -89,19 +122,18 @@ jobs:
- name: Create the package structure
run: |
sudo mkdir -p pkg/usr/lib/
sudo mkdir -p pkg/DEBIAN
sudo cp -r --no-preserve ownership dist pkg/usr/lib/kyoo
sudo install -Dm 644 deployment/kyoo.service -t pkg/usr/lib/systemd/system/
sudo install -Dm 644 deployment/kyoo.sysusers pkg/usr/lib/sysusers.d/kyoo.conf
sudo install -Dm 644 deployment/kyoo.tmpfiles pkg/usr/lib/tmpfiles.d/kyoo.conf
sudo install -Dm 755 deployment/postinst -t pkg/DEBIAN/
- uses: jiro4989/build-deb-action@v2
- name: Build debian package
uses: jiro4989/build-deb-action@v2
with:
package: kyoo
package_root: pkg
maintainer: Zoe Roux <zoe.roux@sdg.moe>
version: ${{env.version}}
depends: "postgresql, libavutil-dev, libavcodec-dev, libavformat-dev"
depends: "libavutil-dev, libavcodec-dev, libavformat-dev"
arch: amd64
desc: ${{env.description}}
- name: Build rpm package

View File

@ -1,6 +1,5 @@
name: Docker
on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]
jobs:
build:

View File

@ -0,0 +1,31 @@
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

@ -93,14 +93,5 @@ namespace Kyoo.Abstractions.Controllers
{
// Skipped
}
/// <summary>
/// An optional callback function called when the startups ends and this plugin has been flagged has disabled.
/// It allow a plugin to log an error or warning message to inform why it has been disabled.
/// </summary>
void Disabled()
{
// Skipped
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Controllers
{

View File

@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Title>Kyoo.Abstractions</Title>
<Authors>Zoe Roux</Authors>
<Description>Base package to create plugins for Kyoo.</Description>

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using JetBrains.Annotations;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Models
{

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Models
{

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Models
{

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Models
{

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Models
{

View File

@ -1,6 +1,7 @@
using Autofac;
using Autofac.Builder;
using Kyoo.Abstractions.Controllers;
using Kyoo.Utils;
using Microsoft.Extensions.Configuration;
namespace Kyoo.Abstractions

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Kyoo
namespace Kyoo.Utils
{
/// <summary>
/// A set of extensions class for enumerable.

View File

@ -8,7 +8,7 @@ using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
namespace Kyoo
namespace Kyoo.Utils
{
/// <summary>
/// A class containing helper methods to merge objects.

View File

@ -1,7 +1,7 @@
using System;
using System.Reflection;
namespace Kyoo
namespace Kyoo.Utils
{
/// <summary>
/// Static class containing MethodOf calls.

View File

@ -2,7 +2,7 @@ using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Kyoo
namespace Kyoo.Utils
{
/// <summary>
/// A class containing helper method for tasks.

View File

@ -9,7 +9,7 @@ using System.Text;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
namespace Kyoo
namespace Kyoo.Utils
{
/// <summary>
/// A set of utility functions that can be used everywhere.

View File

@ -110,6 +110,14 @@ namespace Kyoo.Authentication
CertificateOption certificateOptions = new();
_configuration.GetSection(CertificateOption.Path).Bind(certificateOptions);
clients.AddRange(IdentityContext.GetClients());
foreach (Client client in clients)
{
client.RedirectUris = client.RedirectUris
.Select(x => x.StartsWith("/") ? publicUrl + x : x)
.ToArray();
}
services.AddIdentityServer(options =>
{
options.IssuerUri = publicUrl;
@ -120,7 +128,7 @@ namespace Kyoo.Authentication
.AddInMemoryIdentityResources(IdentityContext.GetIdentityResources())
.AddInMemoryApiScopes(IdentityContext.GetScopes())
.AddInMemoryApiResources(IdentityContext.GetApis())
.AddInMemoryClients(IdentityContext.GetClients().Concat(clients))
.AddInMemoryClients(clients)
.AddProfileService<AccountApi>()
.AddSigninKeys(certificateOptions);

View File

@ -22,7 +22,7 @@
<ItemGroup>
<None Remove="$(LoginRoot)**;" />
<Content Include="$(LoginRoot)**">
<Content Include="$(LoginRoot)**" Visible="false">
<Link>login/%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
namespace Kyoo.Authentication.Models.DTO
{

276
Kyoo.Core/Application.cs Normal file
View File

@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using JetBrains.Annotations;
using Kyoo.Abstractions.Controllers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using Serilog;
using Serilog.Templates;
using Serilog.Templates.Themes;
using ILogger = Serilog.ILogger;
namespace Kyoo.Core
{
public class Application : IApplication
{
/// <summary>
/// The path to the data directory.
/// </summary>
private string _dataDir;
/// <summary>
/// Should the application restart after a shutdown?
/// </summary>
private bool _shouldRestart;
/// <summary>
/// The cancellation token source used to allow the app to be shutdown or restarted.
/// </summary>
private CancellationTokenSource _tokenSource;
/// <summary>
/// The environment in witch Kyoo will run (ether "Production" or "Development").
/// </summary>
private readonly string _environment;
/// <summary>
/// The logger used for startup and error messages.
/// </summary>
private ILogger _logger;
/// <summary>
/// Create a new <see cref="Application"/> that will use the specified environment.
/// </summary>
/// <param name="environment">The environment to run in.</param>
public Application(string environment)
{
_environment = environment;
}
/// <summary>
/// Start the application with the given console args.
/// This is generally called from the Main entrypoint of Kyoo.
/// </summary>
/// <param name="args">The console arguments to use for kyoo.</param>
/// <returns>A task representing the whole process</returns>
public Task Start(string[] args)
{
return Start(args, _ => { });
}
/// <summary>
/// Start the application with the given console args.
/// This is generally called from the Main entrypoint of Kyoo.
/// </summary>
/// <param name="args">The console arguments to use for kyoo.</param>
/// <param name="configure">A custom action to configure the container before the start</param>
/// <returns>A task representing the whole process</returns>
public async Task Start(string[] args, Action<ContainerBuilder> configure)
{
_dataDir = _SetupDataDir(args);
LoggerConfiguration config = new();
_ConfigureLogging(config, null, null);
Log.Logger = config.CreateBootstrapLogger();
_logger = Log.Logger.ForContext<Application>();
AppDomain.CurrentDomain.ProcessExit += (_, _) => Log.CloseAndFlush();
AppDomain.CurrentDomain.UnhandledException += (_, ex)
=> Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception");
do
{
IHost host = _CreateWebHostBuilder(args)
.ConfigureContainer(configure)
.Build();
_tokenSource = new CancellationTokenSource();
await _StartWithHost(host, _tokenSource.Token);
}
while (_shouldRestart);
}
/// <inheritdoc />
public void Shutdown()
{
_shouldRestart = false;
_tokenSource.Cancel();
}
/// <inheritdoc />
public void Restart()
{
_shouldRestart = true;
_tokenSource.Cancel();
}
/// <inheritdoc />
public string GetDataDirectory()
{
return _dataDir;
}
/// <inheritdoc />
public string GetConfigFile()
{
return "./settings.json";
}
/// <summary>
/// Parse the data directory from environment variables and command line arguments, create it if necessary.
/// Set the current directory to said data folder and place a default configuration file if it does not already
/// exists.
/// </summary>
/// <param name="args">The command line arguments</param>
/// <returns>The current data directory.</returns>
private string _SetupDataDir(string[] args)
{
Dictionary<string, string> registry = new();
if (OperatingSystem.IsWindows())
{
object dataDir = Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\SDG\Kyoo\Settings", "DataDir", null)
?? Registry.GetValue(@"HKEY_CURRENT_USER\Software\SDG\Kyoo\Settings", "DataDir", null);
if (dataDir is string data)
registry.Add("DataDir", data);
}
IConfiguration parsed = new ConfigurationBuilder()
.AddInMemoryCollection(registry)
.AddEnvironmentVariables()
.AddEnvironmentVariables("KYOO_")
.AddCommandLine(args)
.Build();
string path = parsed.GetValue<string>("datadir")
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Kyoo");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
Environment.CurrentDirectory = path;
if (!File.Exists(GetConfigFile()))
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, GetConfigFile()),
GetConfigFile());
return path;
}
/// <summary>
/// Start the given host and log failing exceptions.
/// </summary>
/// <param name="host">The host to start.</param>
/// <param name="cancellationToken">A token to allow one to stop the host.</param>
private async Task _StartWithHost(IHost host, CancellationToken cancellationToken)
{
try
{
_logger.Information("Running as {Name}", Environment.UserName);
_logger.Information("Data directory: {DataDirectory}", GetDataDirectory());
await host.RunAsync(cancellationToken);
}
catch (Exception ex)
{
_logger.Fatal(ex, "Unhandled exception");
}
}
/// <summary>
/// Create a a web host
/// </summary>
/// <param name="args">Command line parameters that can be handled by kestrel</param>
/// <returns>A new web host instance</returns>
private IHostBuilder _CreateWebHostBuilder(string[] args)
{
IConfiguration configuration = _SetupConfig(new ConfigurationBuilder(), args).Build();
return new HostBuilder()
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseEnvironment(_environment)
.ConfigureAppConfiguration(x => _SetupConfig(x, args))
.UseSerilog((host, services, builder) => _ConfigureLogging(builder, host.Configuration, services))
.ConfigureServices(x => x.AddRouting())
.ConfigureContainer<ContainerBuilder>(x =>
{
x.RegisterInstance(this).As<IApplication>().SingleInstance().ExternallyOwned();
})
.ConfigureWebHost(x => x
.UseKestrel(options => { options.AddServerHeader = false; })
.UseIIS()
.UseIISIntegration()
.UseUrls(configuration.GetValue<string>("basics:url"))
.UseStartup(host => PluginsStartup.FromWebHost(host, new LoggerFactory().AddSerilog()))
);
}
/// <summary>
/// Register settings.json, environment variables and command lines arguments as configuration.
/// </summary>
/// <param name="builder">The configuration builder to use</param>
/// <param name="args">The command line arguments</param>
/// <returns>The modified configuration builder</returns>
private IConfigurationBuilder _SetupConfig(IConfigurationBuilder builder, string[] args)
{
return builder.SetBasePath(GetDataDirectory())
.AddJsonFile(Path.Join(AppDomain.CurrentDomain.BaseDirectory, GetConfigFile()), false, true)
.AddJsonFile(GetConfigFile(), false, true)
.AddEnvironmentVariables()
.AddEnvironmentVariables("KYOO_")
.AddCommandLine(args);
}
/// <summary>
/// Configure the logging.
/// </summary>
/// <param name="builder">The logger builder to configure.</param>
/// <param name="configuration">The configuration to read settings from.</param>
/// <param name="services">The services to read configuration from.</param>
private void _ConfigureLogging(LoggerConfiguration builder,
[CanBeNull] IConfiguration configuration,
[CanBeNull] IServiceProvider services)
{
if (configuration != null)
{
try
{
builder.ReadFrom.Configuration(configuration, "logging");
}
catch (Exception ex)
{
_logger.Fatal(ex, "Could not read serilog configuration");
}
}
if (services != null)
builder.ReadFrom.Services(services);
const string template =
"[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 15} "
+ "({@i:0000000000})] {@m}{#if not EndsWith(@m, '\n')}\n{#end}{@x}";
builder
.WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code))
.WriteTo.File(
path: Path.Combine(GetDataDirectory(), "logs", "log-.log"),
formatter: new ExpressionTemplate(template),
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true
)
.Enrich.WithThreadId()
.Enrich.FromLogContext();
}
}
}

View File

@ -8,11 +8,11 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Api;
using Kyoo.Core.Api;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
public class ConfigurationManager : IConfigurationManager
{
@ -21,6 +21,11 @@ namespace Kyoo.Controllers
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// The application running Kyoo, it is used to retrieve the configuration file.
/// </summary>
private readonly IApplication _application;
/// <summary>
/// The strongly typed list of options
/// </summary>
@ -31,9 +36,11 @@ namespace Kyoo.Controllers
/// </summary>
/// <param name="configuration">The configuration to use.</param>
/// <param name="references">The strongly typed option list.</param>
public ConfigurationManager(IConfiguration configuration, IEnumerable<ConfigurationReference> references)
/// <param name="application">The application running Kyoo, it is used to retrieve the configuration file.</param>
public ConfigurationManager(IConfiguration configuration, IEnumerable<ConfigurationReference> references, IApplication application)
{
_configuration = configuration;
_application = application;
_references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase);
}
@ -131,7 +138,7 @@ namespace Kyoo.Controllers
IDictionary<string, object> configDic = config;
configDic[path] = value;
JObject obj = JObject.FromObject(config);
await using StreamWriter writer = new(Program.JsonConfigPath);
await using StreamWriter writer = new(_application.GetConfigFile());
await writer.WriteAsync(obj.ToString());
}

View File

@ -9,11 +9,11 @@ using JetBrains.Annotations;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A composite that merge every <see cref="IFileSystem"/> available

View File

@ -9,7 +9,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A <see cref="IFileSystem"/> for http/https links.

View File

@ -5,12 +5,12 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A <see cref="IFileSystem"/> for the local filesystem (using System.IO).

View File

@ -6,8 +6,9 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Utils;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
public class LibraryManager : ILibraryManager
{

View File

@ -2,7 +2,7 @@ using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A permission validator that always validate permissions. This effectively disable the permission system.

View File

@ -5,12 +5,12 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Kyoo.Abstractions.Controllers;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// An implementation of <see cref="IPluginManager"/>.
@ -21,7 +21,7 @@ namespace Kyoo.Controllers
/// <summary>
/// The service provider. It allow plugin's activation.
/// </summary>
private IServiceProvider _provider;
private readonly IServiceProvider _provider;
/// <summary>
/// The configuration to get the plugin's directory.
/// </summary>
@ -51,14 +51,6 @@ namespace Kyoo.Controllers
_logger = logger;
}
public void SetProvider(IServiceProvider provider)
{
// TODO temporary bullshit to inject services before the configure asp net.
// TODO should rework this when the host will be reworked, as well as the asp net configure.
_provider = provider;
}
/// <inheritdoc />
public T GetPlugin<T>(string name)
{
@ -111,16 +103,13 @@ namespace Kyoo.Controllers
_logger.LogTrace("Loading new plugins...");
string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories);
IPlugin[] newPlugins = plugins
_plugins.AddRange(plugins
.Concat(pluginsPaths.SelectMany(LoadPlugin))
.Where(x => x.Enabled)
.GroupBy(x => x.Name)
.Select(x => x.First())
.ToArray();
_plugins.AddRange(newPlugins.Where(x => x.Enabled));
foreach (IPlugin plugin in newPlugins.Where(x => !x.Enabled))
plugin.Disabled();
);
if (!_plugins.Any())
_logger.LogInformation("No plugin enabled");
else

View File

@ -4,9 +4,10 @@ using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
using Microsoft.Extensions.Logging;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A metadata provider composite that merge results from all available providers.

View File

@ -7,11 +7,12 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Models.Options;
using Kyoo.Models.Watch;
using Kyoo.Core.Models.Options;
using Kyoo.Core.Models.Watch;
using Kyoo.Utils;
using Microsoft.Extensions.Options;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// An identifier that use a regex to extract basics metadata.

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle collections

View File

@ -7,9 +7,10 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle episodes.

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository for genres.

View File

@ -9,7 +9,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle library items.

View File

@ -6,9 +6,10 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle libraries.

View File

@ -8,10 +8,11 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Api;
using Kyoo.Utils;
using Kyoo.Core.Api;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A base class to create repositories using Entity Framework.

View File

@ -7,9 +7,10 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle people.

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle providers.

View File

@ -9,7 +9,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle seasons.

View File

@ -5,10 +5,11 @@ using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle shows

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle studios

View File

@ -7,7 +7,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A local repository to handle tracks.

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A repository for users.

View File

@ -10,12 +10,12 @@ using JetBrains.Annotations;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A service to handle long running tasks and a background runner.

View File

@ -7,7 +7,7 @@ using Kyoo.Abstractions.Models;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
/// <summary>
/// Download images and retrieve the path of those images for a resource.

View File

@ -4,14 +4,14 @@ using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
using Stream = Kyoo.Models.Watch.Stream;
using Stream = Kyoo.Core.Models.Watch.Stream;
// We use threads so tasks are not always awaited.
#pragma warning disable 4014
namespace Kyoo.Controllers
namespace Kyoo.Core.Controllers
{
public class BadTranscoderException : Exception {}
@ -22,29 +22,40 @@ namespace Kyoo.Controllers
private const string TranscoderPath = "transcoder";
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
public static extern int init();
private static extern int init();
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
public static extern int transmux(string path, string outpath, out float playableDuration);
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
public static extern int transcode(string path, string outpath, out float playableDuration);
public static int Init() => init();
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
private static extern int transmux(string path, string outpath, out float playableDuration);
public static int Transmux(string path, string outPath, out float playableDuration)
{
path = path.Replace('\\', '/');
outPath = outPath.Replace('\\', '/');
return transmux(path, outPath, out playableDuration);
}
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
private static extern IntPtr extract_infos(string path,
string outpath,
out int length,
out int trackCount,
out uint length,
out uint trackCount,
bool reextracct);
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
private static extern void free(IntPtr ptr);
private static extern void free_streams(IntPtr streams, uint count);
public static Track[] ExtractInfos(string path, string outPath, bool reextract)
{
int size = Marshal.SizeOf<Stream>();
IntPtr ptr = extract_infos(path, outPath, out int arrayLength, out int trackCount, reextract);
path = path.Replace('\\', '/');
outPath = outPath.Replace('\\', '/');
int size = Marshal.SizeOf<Models.Watch.Stream>();
IntPtr ptr = extract_infos(path, outPath, out uint arrayLength, out uint trackCount, reextract);
IntPtr streamsPtr = ptr;
Track[] tracks;
@ -55,7 +66,7 @@ namespace Kyoo.Controllers
int j = 0;
for (int i = 0; i < arrayLength; i++)
{
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
Models.Watch.Stream stream = Marshal.PtrToStructure<Models.Watch.Stream>(streamsPtr);
if (stream!.Type != StreamType.Unknown)
{
tracks[j] = stream.ToTrack();
@ -68,7 +79,7 @@ namespace Kyoo.Controllers
tracks = Array.Empty<Track>();
if (ptr != IntPtr.Zero)
free(ptr); // free_streams is not necessary since the Marshal free the unmanaged pointers.
free_streams(ptr, trackCount);
return tracks;
}
}
@ -83,7 +94,7 @@ namespace Kyoo.Controllers
_options = options;
_library = library;
if (TranscoderAPI.init() != Marshal.SizeOf<Stream>())
if (TranscoderAPI.Init() != Marshal.SizeOf<Models.Watch.Stream>())
throw new BadTranscoderException();
}
@ -122,8 +133,7 @@ namespace Kyoo.Controllers
Task.Factory.StartNew(() =>
{
string cleanManifest = manifest.Replace('\\', '/');
transmuxFailed = TranscoderAPI.transmux(episode.Path, cleanManifest, out playableDuration) != 0;
transmuxFailed = TranscoderAPI.Transmux(episode.Path, manifest, out playableDuration) != 0;
}, TaskCreationOptions.LongRunning);
while (playableDuration < 10 || !File.Exists(manifest) && !transmuxFailed)
await Task.Delay(10);

View File

@ -7,19 +7,20 @@ using Autofac.Extras.AttributeMetadata;
using Kyoo.Abstractions;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Api;
using Kyoo.Controllers;
using Kyoo.Core.Api;
using Kyoo.Core.Controllers;
using Kyoo.Core.Models.Options;
using Kyoo.Core.Tasks;
using Kyoo.Database;
using Kyoo.Models.Options;
using Kyoo.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using IMetadataProvider = Kyoo.Abstractions.Controllers.IMetadataProvider;
namespace Kyoo
namespace Kyoo.Core
{
/// <summary>
/// The core module containing default implementations
@ -70,10 +71,11 @@ namespace Kyoo
builder.RegisterType<LocalFileSystem>().As<IFileSystem>().SingleInstance();
builder.RegisterType<HttpFileSystem>().As<IFileSystem>().SingleInstance();
builder.RegisterType<TaskManager>().As<ITaskManager>().As<IHostedService>().SingleInstance();
builder.RegisterType<ConfigurationManager>().As<IConfigurationManager>().SingleInstance();
builder.RegisterType<Transcoder>().As<ITranscoder>().SingleInstance();
builder.RegisterType<ThumbnailsManager>().As<IThumbnailsManager>().InstancePerLifetimeScope();
builder.RegisterType<TaskManager>().As<ITaskManager>().SingleInstance();
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
builder.RegisterType<RegexIdentifier>().As<IIdentifier>().SingleInstance();
@ -135,8 +137,6 @@ namespace Kyoo
});
services.AddHttpClient();
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
}
/// <inheritdoc />
@ -152,6 +152,7 @@ namespace Kyoo
app.UseHsts();
}
}, SA.Before),
SA.New<IApplicationBuilder>(app => app.UseSerilogRequestLogging(), SA.Before),
SA.New<IApplicationBuilder>(app => app.UseResponseCompression(), SA.Routing + 1),
SA.New<IApplicationBuilder>(app => app.UseRouting(), SA.Routing),
SA.New<IApplicationBuilder>(app => app.UseEndpoints(x => x.MapControllers()), SA.Endpoint)

View File

@ -2,7 +2,7 @@ using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Kyoo
namespace Kyoo.Core
{
public static class Helper
{

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -7,10 +7,9 @@
<Company>SDG</Company>
<Authors>Zoe Roux</Authors>
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
<StartupObject>Kyoo.Program</StartupObject>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<IsWindows Condition="$([MSBuild]::IsOSPlatform('Windows'))">true</IsWindows>
<IsOSX Condition="$([MSBuild]::IsOSPlatform('OSX'))">true</IsOSX>
@ -18,12 +17,16 @@
</PropertyGroup>
<PropertyGroup>
<TranscoderBinary Condition="'$(IsWindows)' == 'true'">transcoder.dll</TranscoderBinary>
<TranscoderBinary Condition="'$(IsOSX)' == 'true'">libtranscoder.dylib</TranscoderBinary>
<TranscoderBinary Condition="'$(IsLinux)' == 'true'">libtranscoder.so</TranscoderBinary>
<TranscoderBinary Condition="$(IsWindows) == true">transcoder.dll</TranscoderBinary>
<TranscoderBinary Condition="$(IsOSX) == true">libtranscoder.dylib</TranscoderBinary>
<TranscoderBinary Condition="$(IsLinux) == true">libtranscoder.so</TranscoderBinary>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
<PackageReference Include="Serilog.Expressions" Version="3.2.0" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="Autofac" Version="6.2.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
@ -35,7 +38,7 @@
<ItemGroup>
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
<ProjectReference Include="..\Kyoo.Database\Kyoo.Database.csproj" />
<ProjectReference Include="../Kyoo.Database/Kyoo.Database.csproj" />
<ProjectReference Include="../Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj" />
<ProjectReference Include="../Kyoo.TheTvdb/Kyoo.TheTvdb.csproj" />
<ProjectReference Include="../Kyoo.Postgresql/Kyoo.Postgresql.csproj" />
@ -44,9 +47,14 @@
<ProjectReference Include="../Kyoo.WebApp/Kyoo.WebApp.csproj" />
</ItemGroup>
<Target Name="BuildTranscoder" BeforeTargets="BeforeBuild" Condition="'$(SkipTranscoder)' != 'true'">
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' != 'true'" Command="mkdir -p build %26%26 cd build %26%26 cmake .. %26%26 make -j" />
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' == 'true'" Command="(if not exist build mkdir build) %26%26 cd build %26%26 cmake .. -G &quot;NMake Makefiles&quot; %26%26 nmake" />
<Target Name="BuildTranscoder" BeforeTargets="BeforeBuild" Condition="'$(SkipTranscoder)' != 'true' And !Exists('$(TranscoderRoot)/build/$(TranscoderBinary)')">
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' != 'true'" Command="mkdir -p build %26%26 cd build %26%26 cmake .. %26%26 make -j" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' == 'true'" Command="(if not exist build mkdir build) %26%26 cd build %26%26 cmake .. -G &quot;NMake Makefiles&quot; %26%26 nmake" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="An environement capable of building the transcoder was not found. Appropriate tools are not installed, not available in the $PATH or not correctly configured. To fix this you can ether:&#xA; - Fix your tools&#xA; - Skip the transcoder via the '-p:SkipTranscoder=true'&#xA; - Download an already built transcoder and put it in ./Kyoo.Transcoder/build" />
</Target>
<ItemGroup Condition="'$(SkipTranscoder)' != 'true'">
@ -55,4 +63,9 @@
<Visible>false</Visible>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="../LICENSE" CopyToOutputDirectory="Always" Visible="false" />
<Content Include="settings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
namespace Kyoo.Models.Watch
namespace Kyoo.Core.Models.Watch
{
/// <summary>
/// A static class allowing one to identify files extensions.

View File

@ -1,7 +1,7 @@
using Kyoo.Abstractions.Models;
using System;
namespace Kyoo.Models.Options
namespace Kyoo.Core.Models.Options
{
/// <summary>
/// The typed list of basic/global options for Kyoo

View File

@ -1,4 +1,4 @@
namespace Kyoo.Models.Options
namespace Kyoo.Core.Models.Options
{
/// <summary>
/// Options for media registering.

View File

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Kyoo.Models.Options
namespace Kyoo.Core.Models.Options
{
/// <summary>
/// Options related to tasks

View File

@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
namespace Kyoo.Models.Watch
namespace Kyoo.Core.Models.Watch
{
/// <summary>
/// The unmanaged stream that the transcoder will return.

View File

@ -5,13 +5,14 @@ using Autofac;
using Kyoo.Abstractions;
using Kyoo.Abstractions.Controllers;
using Kyoo.Authentication;
using Kyoo.Controllers;
using Kyoo.Models.Options;
using Kyoo.Core.Controllers;
using Kyoo.Core.Models.Options;
using Kyoo.Core.Tasks;
using Kyoo.Postgresql;
using Kyoo.SqLite;
using Kyoo.Tasks;
using Kyoo.TheMovieDb;
using Kyoo.TheTvdb;
using Kyoo.Utils;
using Kyoo.WebApp;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@ -21,7 +22,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo
namespace Kyoo.Core
{
/// <summary>
/// The Startup class is used to configure the AspNet's webhost.
@ -131,19 +132,13 @@ namespace Kyoo
/// This is meant to be used from <see cref="WebHostBuilderExtensions.UseStartup"/>.
/// </summary>
/// <param name="host">The context of the web host.</param>
/// <param name="loggingConfiguration">
/// The method used to configure the logger factory used by the plugin manager and plugins during startup.
/// <param name="logger">
/// The logger factory used to log while the application is setting itself up.
/// </param>
/// <returns>A new <see cref="PluginsStartup"/>.</returns>
public static PluginsStartup FromWebHost(WebHostBuilderContext host,
Action<HostBuilderContext, ILoggingBuilder> loggingConfiguration)
ILoggerFactory logger)
{
HostBuilderContext genericHost = new(new Dictionary<object, object>())
{
Configuration = host.Configuration,
HostingEnvironment = host.HostingEnvironment
};
ILoggerFactory logger = LoggerFactory.Create(builder => loggingConfiguration(genericHost, builder));
HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger);
PluginManager plugins = new(
hostProvider,

View File

@ -7,10 +7,10 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Models.Watch;
using Kyoo.Core.Models.Watch;
using Microsoft.Extensions.Logging;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task to add new video files.
@ -146,7 +146,7 @@ namespace Kyoo.Tasks
string[] subtitles = files
.Where(FileExtensions.IsSubtitle)
.Where(x => !x.Contains("/Extra/"))
.Where(x => !x.Contains("Extra"))
.Where(x => tracks.All(y => y.Path != x))
.ToArray();
percent = 0;

View File

@ -6,7 +6,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Microsoft.Extensions.Logging;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task to remove orphaned episode and series.

View File

@ -6,7 +6,7 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task that download metadata providers images.

View File

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task run on Kyoo's startup to initialize plugins

View File

@ -7,7 +7,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task to register a new episode

View File

@ -6,7 +6,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Tasks
namespace Kyoo.Core.Tasks
{
/// <summary>
/// A task to register a new episode

View File

@ -7,10 +7,10 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/collection")]
[Route("api/collections")]

View File

@ -5,7 +5,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
/// <summary>
/// An API to retrieve or edit configuration settings

View File

@ -7,10 +7,10 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/episode")]
[Route("api/episodes")]

View File

@ -5,11 +5,11 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/genre")]
[Route("api/genres")]

View File

@ -6,7 +6,7 @@ using System.Linq.Expressions;
using System.Reflection;
using Kyoo.Abstractions.Models;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
public static class ApiHelper
{

View File

@ -8,7 +8,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[ApiController]
[ResourceView]

View File

@ -6,11 +6,12 @@ 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.Api
namespace Kyoo.Core.Api
{
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
{

View File

@ -6,12 +6,13 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
public class ResourceViewAttribute : ActionFilterAttribute
{

View File

@ -6,10 +6,10 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/library")]
[Route("api/libraries")]

View File

@ -6,11 +6,11 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/item")]
[Route("api/items")]

View File

@ -5,11 +5,11 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/people")]
[ApiController]

View File

@ -2,11 +2,11 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/provider")]
[Route("api/providers")]

View File

@ -5,7 +5,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/search/{query}")]
[ApiController]

View File

@ -6,10 +6,10 @@ using System.Linq;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/season")]
[Route("api/seasons")]

View File

@ -8,10 +8,10 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/show")]
[Route("api/shows")]

View File

@ -5,11 +5,11 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/studio")]
[Route("api/studios")]

View File

@ -7,7 +7,7 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("subtitle")]
[ApiController]

View File

@ -5,7 +5,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/task")]
[Route("api/tasks")]

View File

@ -4,11 +4,11 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/track")]
[Route("api/tracks")]

View File

@ -5,11 +5,11 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Models.Options;
using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("video")]
[ApiController]

View File

@ -5,7 +5,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
namespace Kyoo.Core.Api
{
[Route("api/watch")]
[ApiController]

View File

@ -30,12 +30,14 @@
},
"logging": {
"logLevel": {
"default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "None",
"Kyoo": "Trace"
"MinimumLevel": {
"Default": "Warning",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Fatal",
"Kyoo": "Verbose"
}
}
},
@ -45,12 +47,12 @@
"scan": "24:00:00"
}
},
"media": {
"regex": [
"^\\/?(?<Collection>.+)?\\/(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?\\/\\k<Show>(?: \\(\\d+\\))? S(?<Season>\\d+)E(?<Episode>\\d+)\\..*$",
"^\\/?(?<Collection>.+)?\\/(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?\\/\\k<Show>(?: \\(\\d+\\))? (?<Absolute>\\d+)\\..*$",
"^\\/?(?<Collection>.+)?\\/(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?\\/\\k<Show>(?: \\(\\d+\\))?\\..*$"
"^[\\/\\\\]*(?<Collection>.+)?[\\/\\\\]+(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?[\\/\\\\]+\\k<Show>(?: \\(\\d+\\))? S(?<Season>\\d+)E(?<Episode>\\d+)\\..*$",
"^[\\/\\\\]*(?<Collection>.+)?[\\/\\\\]+(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?[\\/\\\\]+\\k<Show>(?: \\(\\d+\\))? (?<Absolute>\\d+)\\..*$",
"^[\\/\\\\]*(?<Collection>.+)?[\\/\\\\]+(?<Show>.+?)(?: \\((?<StartYear>\\d+)\\))?[\\/\\\\]+\\k<Show>(?: \\(\\d+\\))?\\..*$"
],
"subtitleRegex": [
"^(?<Episode>.+)\\.(?<Language>\\w{1,3})\\.(?<Default>default\\.)?(?<Forced>forced\\.)?.*$"
@ -72,9 +74,9 @@
},
"tvdb": {
"apiKey": "REDACTED"
"apiKey": ""
},
"the-moviedb": {
"apiKey": "REDACTED"
"apiKey": ""
}
}

View File

@ -1,7 +1,7 @@
using System.Data.Common;
using Microsoft.Extensions.Configuration;
namespace Kyoo
namespace Kyoo.Database
{
/// <summary>
/// A class that regroup extensions used by some asp-net related parts of the app.

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<StartupObject>Kyoo.Host.Console.Program</StartupObject>
<Company>SDG</Company>
<Authors>Zoe Roux</Authors>
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="$(IncludeConsole) == true">
<!--
IncludeConsole is a property used when deploying the windows host. Since the runtime identifier is removed,
we specify it manually. This is kindy hacky but MsBuild does not really work well with multiples exe output
and we need multiples exe with the same shared framework (SelfContained).
-->
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Kyoo.Core/Kyoo.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,31 @@
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

@ -0,0 +1,12 @@
<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

@ -0,0 +1,26 @@
<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

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Project file used instead of the default csproj when the host system is windows.
This is the real csproj used to compile the project.
-->
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<RootNamespace>Kyoo.WindowsHost</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Kyoo.Core/Kyoo.Core.csproj" />
<ProjectReference Include="../Kyoo.Host.Console/Kyoo.Host.Console.csproj" Condition="$(IncludeConsole) == true" />
</ItemGroup>
<ItemGroup>
<None Remove="kyoo.ico"/>
<Content Include="kyoo.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -0,0 +1,32 @@
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

@ -0,0 +1,163 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Autofac;
using Kyoo.Abstractions.Controllers;
using Kyoo.Core.Models.Options;
using Microsoft.Extensions.Options;
namespace Kyoo.Host.WindowsTrait
{
/// <summary>
/// A singleton that add an notification icon on the window's toolbar.
/// </summary>
public sealed class SystemTrait : IStartable, IDisposable
{
/// <summary>
/// The application running Kyoo.
/// </summary>
private readonly IApplication _application;
/// <summary>
/// The options containing the <see cref="BasicOptions.PublicUrl"/>.
/// </summary>
private readonly IOptions<BasicOptions> _options;
/// <summary>
/// The thread where the trait is running.
/// </summary>
private Thread _thread;
/// <summary>
/// Create a new <see cref="SystemTrait"/>.
/// </summary>
/// <param name="application">The application running Kyoo.</param>
/// <param name="options">The options to use.</param>
public SystemTrait(IApplication application, IOptions<BasicOptions> options)
{
_application = application;
_options = options;
}
/// <inheritdoc />
public void Start()
{
_thread = new Thread(() => InternalSystemTrait.Run(_application, _options))
{
IsBackground = true
};
_thread.Start();
}
/// <inheritdoc />
public void Dispose()
{
System.Windows.Forms.Application.Exit();
_thread?.Join();
_thread = null;
}
/// <summary>
/// The internal class for <see cref="SystemTrait"/>. It should be invoked via
/// <see cref="InternalSystemTrait.Run"/>.
/// </summary>
private class InternalSystemTrait : ApplicationContext
{
/// <summary>
/// The application running Kyoo.
/// </summary>
private readonly IApplication _application;
/// <summary>
/// The options containing the <see cref="BasicOptions.PublicUrl"/>.
/// </summary>
private readonly IOptions<BasicOptions> _options;
/// <summary>
/// The Icon that is displayed in the window's bar.
/// </summary>
private readonly NotifyIcon _icon;
/// <summary>
/// Create a new <see cref="InternalSystemTrait"/>. Used only by <see cref="Run"/>.
/// </summary>
/// <param name="application">The application running Kyoo.</param>
/// <param name="options">The option containing the public url.</param>
private InternalSystemTrait(IApplication application, IOptions<BasicOptions> options)
{
_application = application;
_options = options;
AppDomain.CurrentDomain.ProcessExit += (_, _) => Dispose();
System.Windows.Forms.Application.ApplicationExit += (_, _) => Dispose();
_icon = new NotifyIcon();
_icon.Text = "Kyoo";
_icon.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "kyoo.ico"));
_icon.Visible = true;
_icon.MouseClick += (_, e) =>
{
if (e.Button != MouseButtons.Left)
return;
_StartBrowser();
};
_icon.ContextMenuStrip = new ContextMenuStrip();
_icon.ContextMenuStrip.Items.AddRange(new ToolStripItem[]
{
new ToolStripMenuItem("Open browser", null, (_, _) => { _StartBrowser(); }),
new ToolStripMenuItem("Open logs", null, (_, _) => { _OpenLogs(); }),
new ToolStripSeparator(),
new ToolStripMenuItem("Exit", null, (_, _) => { _application.Shutdown(); })
});
}
/// <summary>
/// Run the trait in the current thread, this method does not return while the trait is running.
/// </summary>
/// <param name="application">The application running Kyoo.</param>
/// <param name="options">The options to pass to <see cref="InternalSystemTrait"/>.</param>
public static void Run(IApplication application, IOptions<BasicOptions> options)
{
using InternalSystemTrait trait = new(application, options);
System.Windows.Forms.Application.Run(trait);
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
_icon.Visible = false;
base.Dispose(disposing);
_icon.Dispose();
}
/// <summary>
/// Open kyoo's page in the user's default browser.
/// </summary>
private void _StartBrowser()
{
Process browser = new()
{
StartInfo = new ProcessStartInfo(_options.Value.PublicUrl.ToString())
{
UseShellExecute = true
}
};
browser.Start();
}
/// <summary>
/// Open the log directory in windows's explorer.
/// </summary>
private void _OpenLogs()
{
string logDir = Path.Combine(_application.GetDataDirectory(), "logs");
Process.Start("explorer.exe", logDir);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -5,6 +5,7 @@ using System.Reflection;
using EFCore.NamingConventions.Internal;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
using Npgsql;

View File

@ -4,6 +4,7 @@ using System.Linq.Expressions;
using System.Reflection;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
using TMDbLib.Objects.Search;
namespace Kyoo.TheMovieDb

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
using TMDbLib.Objects.Movies;
using TMDbLib.Objects.Search;

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