Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
63ba8d30ac | |||
6e00fae9b2 | |||
091db6afeb | |||
52fe269832 | |||
d146406e5d | |||
b1514c208e | |||
f046ef5d3e | |||
761aab3e9e | |||
b0654474c4 | |||
8e7c2a7374 |
15 changed files with 218 additions and 14 deletions
.dockerignore.editorconfig
.forgejo
EllieHub.slnEllieHub
README.md
39
.dockerignore
Normal file
39
.dockerignore
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# .NET
|
||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
**/out/
|
||||||
|
|
||||||
|
# Node
|
||||||
|
**/node_modules/
|
||||||
|
**/npm-debug.log
|
||||||
|
**/dist/
|
||||||
|
|
||||||
|
# Version control
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# IDEs
|
||||||
|
**/.vscode/
|
||||||
|
**/.idea/
|
||||||
|
**/*.swp
|
||||||
|
**/*.swo
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
**/.env
|
||||||
|
**/.env.local
|
||||||
|
**/.env.*
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
**/coverage
|
||||||
|
**/*.test.js
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
**/.DS_Store
|
||||||
|
|
||||||
|
# Files
|
||||||
|
Dockerfile*
|
||||||
|
**/*.trx
|
||||||
|
**/*.md
|
||||||
|
**/*.ps1
|
||||||
|
**/*.cmd
|
||||||
|
**/*.sh
|
|
@ -95,7 +95,8 @@ dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
|
||||||
|
|
||||||
# Modifier preferences
|
# Modifier preferences
|
||||||
dotnet_style_require_accessibility_modifiers = always:error
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
|
||||||
|
dotnet_diagnostics.IDE0040.severity = warning
|
||||||
|
|
||||||
# Expression-level preferences
|
# Expression-level preferences
|
||||||
dotnet_style_coalesce_expression = true
|
dotnet_style_coalesce_expression = true
|
||||||
|
|
56
.forgejo/issue_template/bug_report.yml
Normal file
56
.forgejo/issue_template/bug_report.yml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: File a bug report.
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: Which version of EllieHub are you using?
|
||||||
|
multiple: false
|
||||||
|
options:
|
||||||
|
- "Windows x64"
|
||||||
|
- "Windows arm64"
|
||||||
|
- "Linux x64"
|
||||||
|
- "Linux arm64"
|
||||||
|
- "MacOS x64"
|
||||||
|
- "MacOS arm64"
|
||||||
|
- "I compiled from source"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Description"
|
||||||
|
description: "Give a concise description of the problem"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Reproduction Steps"
|
||||||
|
description: "Enumerate the steps needed to reproduce the behavior"
|
||||||
|
value: "1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Expected Behavior"
|
||||||
|
description: "Describe what you expected to happen"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Actual Behavior"
|
||||||
|
description: "Describe what actually happened"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Screenshots"
|
||||||
|
description: "If applicable, add screenshots to help explain your problem"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Notes"
|
||||||
|
description: "Add any other context about the problem here"
|
||||||
|
placeholder: "eg. OS version, etc"
|
||||||
|
validations:
|
||||||
|
required: false
|
30
.forgejo/issue_template/feature_request.yml
Normal file
30
.forgejo/issue_template/feature_request.yml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
name: "Feature Request"
|
||||||
|
description: Suggest an idea for this project.
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: "textarea"
|
||||||
|
attributes:
|
||||||
|
label: "Is your feature request related to a problem?"
|
||||||
|
description: "If so, describe what the problem is"
|
||||||
|
placeholder: "eg. I'm always frustrated when [...]"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: "textarea"
|
||||||
|
attributes:
|
||||||
|
label: "Describe the feature you'd like"
|
||||||
|
description: "Describe what you want to happen"
|
||||||
|
placeholder: "eg. The application should do [...] then [...]"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: "textarea"
|
||||||
|
attributes:
|
||||||
|
label: "What alternatives have you considered?"
|
||||||
|
description: "Feel free to mention similar applications if you feel this will get your point across better"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: "textarea"
|
||||||
|
attributes:
|
||||||
|
label: "Additional context"
|
||||||
|
description: "Add any other context or screenshots about the feature request here"
|
||||||
|
validations:
|
||||||
|
required: false
|
0
.forgejo/readme_assets/.gitkeep
Normal file
0
.forgejo/readme_assets/.gitkeep
Normal file
|
@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieHub", "EllieHub\EllieH
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2A553F1B-5A2C-43D6-A145-F219530326D3}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2A553F1B-5A2C-43D6-A145-F219530326D3}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.dockerignore = .dockerignore
|
||||||
|
EllieHub\Dockerfile = EllieHub\Dockerfile
|
||||||
release.ps1 = release.ps1
|
release.ps1 = release.ps1
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|
|
@ -18,5 +18,5 @@ public static class AppConstants
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name for an <see cref="HttpClient"/> that makes calls to the Toastielab API.
|
/// The name for an <see cref="HttpClient"/> that makes calls to the Toastielab API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ToastielabClient = "NoRedirect";
|
public const string ToastielabClient = "ToastielabClient";
|
||||||
}
|
}
|
19
EllieHub/Dockerfile
Normal file
19
EllieHub/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Please, see the following url: https://toastielab.dev/EllieBotDevs/EllieHub/wiki/Docker
|
||||||
|
FROM--platform =$BUILDPLATFORM mcr.microsoft.com / dotnet / sdk:9.0 AS base
|
||||||
|
WORKDIR /
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y libsm-dev libice-dev libx11-dev fontconfig \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& useradd -m -u 1000 elliehub_user
|
||||||
|
FROM base AS publish
|
||||||
|
ARG DOTNET_BUILD=Debug
|
||||||
|
WORKDIR /home/elliehub_user/src
|
||||||
|
COPY . .
|
||||||
|
ADD https://toastielab.dev/EllieBotDevs/EllieHub/raw/branch/main/.editorconfig .editorconfig
|
||||||
|
RUN dotnet publish "EllieHub.csproj" -c $DOTNET_BUILD -o /home/elliehub_user/app /p:SelfContained=false /p:PublishSingleFile=false /p:IncludeNativeLibrariesForSelfExtract=false \
|
||||||
|
&& chown -R elliehub_user:elliehub_user /home/elliehub_user
|
||||||
|
FROM base AS final
|
||||||
|
USER elliehub_user
|
||||||
|
WORKDIR /home/elliehub_user/app
|
||||||
|
COPY --from=publish /home/elliehub_user/app .
|
||||||
|
ENTRYPOINT ["dotnet", "EllieHub.dll"]
|
|
@ -20,7 +20,7 @@
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
|
||||||
<!--Version-->
|
<!--Version-->
|
||||||
<VersionPrefix>1.0.4.0</VersionPrefix>
|
<VersionPrefix>1.0.5.0</VersionPrefix>
|
||||||
|
|
||||||
<!--Avalonia Settings-->
|
<!--Avalonia Settings-->
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
|
|
@ -39,7 +39,7 @@ public sealed class FfmpegWindowsResolver : FfmpegResolver
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async ValueTask<string> GetLatestVersionAsync(CancellationToken cToken = default)
|
public override async ValueTask<string> GetLatestVersionAsync(CancellationToken cToken = default)
|
||||||
{
|
{
|
||||||
var http = _httpClientFactory.CreateClient(AppConstants.NoRedirectClient);
|
var http = _httpClientFactory.CreateClient(AppConstants.ToastielabClient);
|
||||||
|
|
||||||
var response = await http.GetAsync("https://github.com/GyanD/codexffmpeg/releases/latest", cToken);
|
var response = await http.GetAsync("https://github.com/GyanD/codexffmpeg/releases/latest", cToken);
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async ValueTask<string> GetLatestVersionAsync(CancellationToken cToken = default)
|
public async ValueTask<string> GetLatestVersionAsync(CancellationToken cToken = default)
|
||||||
{
|
{
|
||||||
var http = _httpClientFactory.CreateClient(AppConstants.NoRedirectClient);
|
var http = _httpClientFactory.CreateClient(AppConstants.ToastielabClient);
|
||||||
|
|
||||||
var response = await http.GetAsync("https://github.com/yt-dlp/yt-dlp/releases/latest", cToken);
|
var response = await http.GetAsync("https://github.com/yt-dlp/yt-dlp/releases/latest", cToken);
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ public sealed partial class EllieResolver : IBotResolver
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var downloadStream = await http.GetStreamAsync(
|
await using var downloadStream = await http.GetStreamAsync(
|
||||||
await GetDownloadUrlAsync(latestVersion, cToken),
|
await GetDownloadUrlAsync(latestVersion, cToken),
|
||||||
cToken
|
cToken
|
||||||
);
|
);
|
||||||
|
@ -185,11 +185,17 @@ public sealed partial class EllieResolver : IBotResolver
|
||||||
// Update settings
|
// Update settings
|
||||||
await _appConfigManager.UpdateBotEntryAsync(Id, x => x with { Version = latestVersion }, cToken);
|
await _appConfigManager.UpdateBotEntryAsync(Id, x => x with { Version = latestVersion }, cToken);
|
||||||
|
|
||||||
// Create creds.yml
|
// Create creds.yml if it doesn't exist
|
||||||
var credsUri = Path.Join(installationUri, "creds.yml");
|
// Old versions have creds.yml and example in ./
|
||||||
|
// New versions have creds.yml and example in ./data/
|
||||||
|
// If downloaded bot has creds example in ./, create creds.yml to ./, else create to ./data/
|
||||||
|
var credsExampleUri = Directory.EnumerateFiles(installationUri, "creds_example.yml", SearchOption.AllDirectories)
|
||||||
|
.Last();
|
||||||
|
|
||||||
|
var credsUri = Path.Join(Directory.GetParent(credsExampleUri)?.FullName ?? Path.Join(installationUri, "data"), "creds.yml");
|
||||||
|
|
||||||
if (!File.Exists(credsUri))
|
if (!File.Exists(credsUri))
|
||||||
File.Copy(Path.Join(installationUri, "creds_example.yml"), credsUri);
|
File.Copy(credsExampleUri, credsUri);
|
||||||
|
|
||||||
return (currentVersion, latestVersion);
|
return (currentVersion, latestVersion);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +260,7 @@ public sealed partial class EllieResolver : IBotResolver
|
||||||
using var zipFile = ZipFile.OpenRead(backupFileUri);
|
using var zipFile = ZipFile.OpenRead(backupFileUri);
|
||||||
var zippedFiles = zipFile.Entries
|
var zippedFiles = zipFile.Entries
|
||||||
.Where(x =>
|
.Where(x =>
|
||||||
x.Name is "creds.yml" // Restore creds.yml and everything in the "data" folder, except the stuff in the "strings" folder.
|
x.Name is "creds.yml" // Restore creds.yml and everything in the "data" folder, but not the stuff in the "strings" folder.
|
||||||
|| (!string.IsNullOrWhiteSpace(x.Name) && x.FullName.Contains("data/") && !x.FullName.Contains("strings/"))
|
|| (!string.IsNullOrWhiteSpace(x.Name) && x.FullName.Contains("data/") && !x.FullName.Contains("strings/"))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -264,7 +270,13 @@ public sealed partial class EllieResolver : IBotResolver
|
||||||
.Prepend(Directory.GetParent(installationUri)?.FullName ?? string.Empty)
|
.Prepend(Directory.GetParent(installationUri)?.FullName ?? string.Empty)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
await RestoreFileAsync(zippedFile, Path.Join(fileDestinationPath), cToken);
|
// Old versions have creds.yml and example in ./
|
||||||
|
// New versions have creds.yml and example in ./data/
|
||||||
|
// If downloaded bot has creds example in the root, restore creds.yml to root, else restore to ./data/
|
||||||
|
if (zippedFile.Name is "creds.yml" && !File.Exists(Path.Join(installationUri, "creds_example.yml")))
|
||||||
|
await RestoreFileAsync(zippedFile, Path.Join(installationUri, "data", zippedFile.Name), cToken);
|
||||||
|
else
|
||||||
|
await RestoreFileAsync(zippedFile, Path.Join(fileDestinationPath), cToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -261,8 +261,9 @@ public class BotConfigViewModel : ViewModelBase<BotConfigView>, IDisposable
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Get result from inner directories first, for compatibility with creds.yml being in the root (old versions) and in the data folder (newer versions).
|
||||||
var fileUri = Directory.EnumerateFiles(_appConfigManager.AppConfig.BotEntries[Resolver.Id].InstanceDirectoryUri, fileName, SearchOption.AllDirectories)
|
var fileUri = Directory.EnumerateFiles(_appConfigManager.AppConfig.BotEntries[Resolver.Id].InstanceDirectoryUri, fileName, SearchOption.AllDirectories)
|
||||||
.First(x => x.Contains(fileName, StringComparison.Ordinal));
|
.Last();
|
||||||
|
|
||||||
var process = Process.Start(new ProcessStartInfo()
|
var process = Process.Start(new ProcessStartInfo()
|
||||||
{
|
{
|
||||||
|
|
|
@ -229,11 +229,11 @@ public sealed class AppResolver : IAppResolver
|
||||||
/// <exception cref="InvalidOperationException">Occurs when parsing of the response fails.</exception>
|
/// <exception cref="InvalidOperationException">Occurs when parsing of the response fails.</exception>
|
||||||
private async ValueTask<string> GetLatestVersionFromUrlAsync(CancellationToken cToken = default)
|
private async ValueTask<string> GetLatestVersionFromUrlAsync(CancellationToken cToken = default)
|
||||||
{
|
{
|
||||||
var http = _httpClientFactory.CreateClient(AppConstants.NoRedirectClient);
|
var http = _httpClientFactory.CreateClient(AppConstants.ToastielabClient);
|
||||||
var response = await http.GetAsync(_toastielabReleasesRepoUrl, cToken);
|
var response = await http.GetAsync(_toastielabReleasesRepoUrl, cToken);
|
||||||
|
|
||||||
var lastSlashIndex = response.Headers.Location?.OriginalString.LastIndexOf('/')
|
var lastSlashIndex = response.Headers.Location?.OriginalString.LastIndexOf('/')
|
||||||
?? throw new InvalidOperationException("Failed to get the latest EllieBot version.");
|
?? throw new InvalidOperationException("Failed to get the latest EllieHub version.");
|
||||||
|
|
||||||
return response.Headers.Location.OriginalString[(lastSlashIndex + 1)..];
|
return response.Headers.Location.OriginalString[(lastSlashIndex + 1)..];
|
||||||
}
|
}
|
||||||
|
|
44
README.md
44
README.md
|
@ -1,2 +1,46 @@
|
||||||
# EllieHub
|
# EllieHub
|
||||||
|
|
||||||
|
EllieHub is a cross-platform user-friendly desktop application designed for management of [EllieBot][EllieWebsite] Discord bot instances.
|
||||||
|
|
||||||
|
Download it [here][EllieHubReleases].
|
||||||
|
For more information about this project, please visit the [wiki][ToastielabWiki].
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Install, update, and remove Ellie bots.
|
||||||
|
- Install and update dependencies used by Ellie to play music.
|
||||||
|
- Easy access to the settings of each Ellie bot.
|
||||||
|
- Start and stop your bots directly from the Hub.
|
||||||
|
- Create backups of your bots whenever you want.
|
||||||
|
- Watch logs of your bots in real time and have them saved automatically for later inspection.
|
||||||
|
- Works on Windows, Linux, and macOS.
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
#### Screenshots are coming soon!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
EllieHub, a desktop application for managing instances of the EllieBot Discord bot.
|
||||||
|
|
||||||
|
Copyright (C) 2025 Toastie_t0ast & EllieBotDevs
|
||||||
|
|
||||||
|
This program 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
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
[EllieWebsite]: https://elliebot.net/
|
||||||
|
[HomeView]: ./.forgejo/readme_assets/elliehub_home.png
|
||||||
|
[ConfigView]: ./.forgejo/readme_assets/elliehub_config.png
|
||||||
|
[BotConfigeView]: ./.forgejo/readme_assets/elliehub_botconfig.png
|
||||||
|
[ToastielabWiki]: https://toastielab.dev/EllieBotDevs/EllieHub/wiki
|
||||||
|
[EllieHubReleases]: https://toastielab.dev/EllieBotDevs/EllieHub/releases/latest
|
Loading…
Add table
Reference in a new issue