mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-23 15:30:34 -04:00
WindowsTrait: Creating a custom host for windows with a notification icon. Starting to create a inno setup installer
This commit is contained in:
parent
0187569748
commit
42469bfa67
22
Kyoo.WindowsHost/Kyoo.WindowsHost.csproj
Normal file
22
Kyoo.WindowsHost/Kyoo.WindowsHost.csproj
Normal file
@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<RootNamespace>Kyoo.Host.Windows</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Kyoo/Kyoo.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="kyoo.ico" />
|
||||
<Content Include="kyoo.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
28
Kyoo.WindowsHost/Program.cs
Normal file
28
Kyoo.WindowsHost/Program.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Threading.Tasks;
|
||||
using Autofac;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Kyoo.Host.Windows
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application that overrides the default host (<see cref="Kyoo.Program"/>).
|
||||
/// 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 async Task Main(string[] args)
|
||||
{
|
||||
Kyoo.Program.SetupDataDir(args);
|
||||
|
||||
IHost host = Kyoo.Program.CreateWebHostBuilder(args)
|
||||
.ConfigureContainer<ContainerBuilder>(builder =>
|
||||
{
|
||||
builder.RegisterType<SystemTrait>().As<IStartable>().SingleInstance();
|
||||
})
|
||||
.Build();
|
||||
|
||||
await Kyoo.Program.StartWithHost(host);
|
||||
}
|
||||
}
|
||||
}
|
135
Kyoo.WindowsHost/SystemTrait.cs
Normal file
135
Kyoo.WindowsHost/SystemTrait.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Autofac;
|
||||
using Kyoo.Models.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Kyoo.Host.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// A singleton that add an notification icon on the window's toolbar.
|
||||
/// </summary>
|
||||
public sealed class SystemTrait : IStartable, IDisposable
|
||||
{
|
||||
/// <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="options">The options to use.</param>
|
||||
public SystemTrait(IOptions<BasicOptions> options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Start()
|
||||
{
|
||||
_thread = new Thread(() => InternalSystemTrait.Run(_options))
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
// TODO not sure that the trait is ended and that it does shutdown but the only way to shutdown the
|
||||
// app anyway is via the Trait's Exit or a Signal so it's fine.
|
||||
_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 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="options">The option containing the public url.</param>
|
||||
private InternalSystemTrait(IOptions<BasicOptions> options)
|
||||
{
|
||||
_options = options;
|
||||
|
||||
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("Exit", null, (_, _) => { Environment.Exit(0); })
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the trait in the current thread, this method does not return while the trait is running.
|
||||
/// </summary>
|
||||
/// <param name="options">The options to pass to <see cref="InternalSystemTrait"/>.</param>
|
||||
public static void Run(IOptions<BasicOptions> options)
|
||||
{
|
||||
using InternalSystemTrait trait = new(options);
|
||||
Application.Run(trait);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
_icon.Visible = false;
|
||||
_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
Kyoo.WindowsHost/kyoo.ico
Normal file
BIN
Kyoo.WindowsHost/kyoo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
10
Kyoo.sln
10
Kyoo.sln
@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "tests\Kyoo.Te
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.WebApp", "Kyoo.WebApp\Kyoo.WebApp.csproj", "{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.WindowsHost", "Kyoo.WindowsHost\Kyoo.WindowsHost.csproj", "{98851001-40DD-46A6-94B3-2F8D90722076}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -65,5 +67,13 @@ Global
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{98851001-40DD-46A6-94B3-2F8D90722076}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{98851001-40DD-46A6-94B3-2F8D90722076}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{98851001-40DD-46A6-94B3-2F8D90722076}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{98851001-40DD-46A6-94B3-2F8D90722076}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -70,10 +70,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 +136,6 @@ namespace Kyoo
|
||||
});
|
||||
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -44,7 +44,8 @@
|
||||
<ProjectReference Include="../Kyoo.WebApp/Kyoo.WebApp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="BuildTranscoder" BeforeTargets="BeforeBuild" Condition="'$(SkipTranscoder)' != 'true'">
|
||||
<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" />
|
||||
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' == 'true'" Command="(if not exist build mkdir build) %26%26 cd build %26%26 cmake .. -G "NMake Makefiles" %26%26 nmake" />
|
||||
</Target>
|
||||
|
@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SEnvironment = System.Environment;
|
||||
|
||||
namespace Kyoo
|
||||
{
|
||||
@ -33,15 +34,18 @@ namespace Kyoo
|
||||
/// Main function of the program
|
||||
/// </summary>
|
||||
/// <param name="args">Command line arguments</param>
|
||||
public static async Task Main(string[] args)
|
||||
public static Task Main(string[] args)
|
||||
{
|
||||
if (!File.Exists(JsonConfigPath))
|
||||
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, JsonConfigPath), JsonConfigPath);
|
||||
|
||||
IHost host = CreateWebHostBuilder(args)
|
||||
.UseEnvironment(Environment)
|
||||
.Build();
|
||||
SetupDataDir(args);
|
||||
return StartWithHost(CreateWebHostBuilder(args).Build());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the given host and log failing exceptions.
|
||||
/// </summary>
|
||||
/// <param name="host">The host to start.</param>
|
||||
public static async Task StartWithHost(IHost host)
|
||||
{
|
||||
try
|
||||
{
|
||||
host.Services.GetRequiredService<ILogger<Application>>()
|
||||
@ -65,6 +69,7 @@ namespace Kyoo
|
||||
return builder.SetBasePath(System.Environment.CurrentDirectory)
|
||||
.AddJsonFile(JsonConfigPath, false, true)
|
||||
.AddEnvironmentVariables()
|
||||
.AddEnvironmentVariables("KYOO_")
|
||||
.AddCommandLine(args);
|
||||
}
|
||||
|
||||
@ -73,7 +78,7 @@ namespace Kyoo
|
||||
/// </summary>
|
||||
/// <param name="context">The host context that contains the configuration</param>
|
||||
/// <param name="builder">The logger builder to configure.</param>
|
||||
private static void _ConfigureLogging(HostBuilderContext context, ILoggingBuilder builder)
|
||||
public static void ConfigureLogging(HostBuilderContext context, ILoggingBuilder builder)
|
||||
{
|
||||
builder.AddConfiguration(context.Configuration.GetSection("logging"))
|
||||
.AddSimpleConsole(x =>
|
||||
@ -89,18 +94,19 @@ namespace Kyoo
|
||||
/// </summary>
|
||||
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
||||
/// <param name="loggingConfiguration">
|
||||
/// An action to configure the logging. If it is null, <see cref="_ConfigureLogging"/> will be used.
|
||||
/// An action to configure the logging. If it is null, <see cref="ConfigureLogging"/> will be used.
|
||||
/// </param>
|
||||
/// <returns>A new web host instance</returns>
|
||||
public static IHostBuilder CreateWebHostBuilder(string[] args,
|
||||
Action<HostBuilderContext, ILoggingBuilder> loggingConfiguration = null)
|
||||
{
|
||||
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
|
||||
loggingConfiguration ??= _ConfigureLogging;
|
||||
loggingConfiguration ??= ConfigureLogging;
|
||||
|
||||
return new HostBuilder()
|
||||
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
||||
.UseEnvironment(Environment)
|
||||
.ConfigureAppConfiguration(x => SetupConfig(x, args))
|
||||
.ConfigureLogging(loggingConfiguration)
|
||||
.ConfigureServices(x => x.AddRouting())
|
||||
@ -113,6 +119,32 @@ namespace Kyoo
|
||||
);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public static void SetupDataDir(string[] args)
|
||||
{
|
||||
IConfiguration parsed = new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables()
|
||||
.AddEnvironmentVariables("KYOO_")
|
||||
.AddCommandLine(args)
|
||||
.Build();
|
||||
|
||||
string path = parsed.GetValue<string>("data_dir");
|
||||
if (path == null)
|
||||
path = Path.Combine(SEnvironment.GetFolderPath(SEnvironment.SpecialFolder.LocalApplicationData), "Kyoo");
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
SEnvironment.CurrentDirectory = path;
|
||||
|
||||
if (!File.Exists(JsonConfigPath))
|
||||
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, JsonConfigPath), JsonConfigPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An useless class only used to have a logger in the main.
|
||||
/// </summary>
|
||||
|
39
deployment/kyoo-windows.iss
Normal file
39
deployment/kyoo-windows.iss
Normal file
@ -0,0 +1,39 @@
|
||||
[Setup]
|
||||
AppId={{31A61284-7939-46BC-B584-D2279A6EEEE8}
|
||||
AppName=Kyoo
|
||||
AppVersion=1.0
|
||||
AppPublisher=SDG
|
||||
AppPublisherURL=https://github.com/AnonymusRaccoon/Kyoo
|
||||
AppSupportURL=https://github.com/AnonymusRaccoon/Kyoo
|
||||
AppUpdatesURL=https://github.com/AnonymusRaccoon/Kyoo
|
||||
DefaultDirName={commonpf}\Kyoo
|
||||
DisableProgramGroupPage=yes
|
||||
LicenseFile={#kyoo}\LICENSE
|
||||
OutputBaseFilename=kyoo-windows
|
||||
SetupIconFile={#kyoo}\wwwroot\favicon.ico
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
AppCopyright=GPL-3.0
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive
|
||||
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
|
||||
|
||||
[Files]
|
||||
Source: "{#kyoo}\Kyoo.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#kyoo}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{commonappdata}\Kyoo"
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\Kyoo"; Filename: "{app}\Kyoo.exe"
|
||||
Name: "{autodesktop}\Kyoo"; Filename: "{app}\Kyoo.exe"; Tasks: desktopicon
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\Kyoo.exe"; Description: "{cm:LaunchProgram,Kyoo}"; Flags: nowait postinstall skipifsilent
|
Loading…
x
Reference in New Issue
Block a user