From 3c88068090bac9d9ea4eca7961700488817fa605 Mon Sep 17 00:00:00 2001 From: Topaz Whitelock <250328010.b@uni-prizren.com> Date: Sat, 1 Aug 2026 07:35:36 +0200 Subject: [PATCH 1/3] Fetch mods from any Git platform. --- .../Services/ModsService.cs | 23 ++++++--- .../Services/RepositoryService.cs | 50 ++++++++++++++++++- .../ViewModels/DownloadableModViewModel.cs | 2 +- .../ViewModels/MainViewModel.cs | 3 +- .../ViewModels/ModViewModel.cs | 16 ++++-- .../Views/InstallModView.xaml | 23 +++++++-- .../Views/InstallModView.xaml.cs | 1 + 7 files changed, 101 insertions(+), 17 deletions(-) diff --git a/OpenKh.Tools.ModsManager/Services/ModsService.cs b/OpenKh.Tools.ModsManager/Services/ModsService.cs index f46cecbd3..018d451bc 100644 --- a/OpenKh.Tools.ModsManager/Services/ModsService.cs +++ b/OpenKh.Tools.ModsManager/Services/ModsService.cs @@ -121,11 +121,12 @@ public static Task InstallMod( bool isLuaFile, Action progressOutput = null, Action progressNumber = null, + string platformUrl = null, string branchName = null) { if (!isZipFile && !isLuaFile) { - return Task.Run(() => InstallModFromGithub(name, progressOutput, progressNumber, branchName)); + return Task.Run(() => InstallModFromGit(name, progressOutput, progressNumber, platformUrl, branchName)); } else if (isZipFile && !isLuaFile) { @@ -277,10 +278,11 @@ public static void InstallModFromZip( } } - public static async Task InstallModFromGithub( + public static async Task InstallModFromGit( string repositoryName, Action progressOutput = null, Action progressNumber = null, + string platformName = null, string branchName = null) { var parts = repositoryName.Split('/'); @@ -294,7 +296,7 @@ public static async Task InstallModFromGithub( if (!string.IsNullOrWhiteSpace(branchName)) { progressOutput?.Invoke($"Fetching file {ModMetadata} from branch {branchName}"); - var isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata); + var isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata, platformName); if (!isValidMod) throw new BranchNotValidException(repositoryName, branchName); } @@ -302,7 +304,7 @@ public static async Task InstallModFromGithub( { branchName = DefaultGitBranch; progressOutput?.Invoke($"Fetching file {ModMetadata} from {branchName}"); - var isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata); + var isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata, platformName); if (!isValidMod) { progressOutput?.Invoke($"{ModMetadata} not found, fetching default branch name"); @@ -311,7 +313,7 @@ public static async Task InstallModFromGithub( throw new RepositoryNotFoundException(repositoryName); progressOutput?.Invoke($"Fetching file {ModMetadata} from {branchName}"); - isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata); + isValidMod = await RepositoryService.IsFileExists(repositoryName, branchName, ModMetadata, platformName); } if (!isValidMod) @@ -363,7 +365,16 @@ await Task.Run(() => return true; }; - Repository.Clone($"https://github.com/{repositoryName}", modPath, options); + var _fetchPlatformUrl = new Uri("https://github.com/"); + var _fetchRelativeUri = new Uri(_fetchPlatformUrl, $"{repositoryName}"); + + if (!String.IsNullOrWhiteSpace(platformName)) + { + _fetchPlatformUrl = new Uri(platformName.Contains("http") ? platformName : "https://" + platformName); + _fetchRelativeUri = new Uri(_fetchPlatformUrl, $"{repositoryName}"); + } + + Repository.Clone(_fetchRelativeUri.ToString(), modPath, options); }); if (IsCollection(repositoryName)) await MoveToCollection(repositoryName); diff --git a/OpenKh.Tools.ModsManager/Services/RepositoryService.cs b/OpenKh.Tools.ModsManager/Services/RepositoryService.cs index ea7b885cd..02b0564e5 100644 --- a/OpenKh.Tools.ModsManager/Services/RepositoryService.cs +++ b/OpenKh.Tools.ModsManager/Services/RepositoryService.cs @@ -1,6 +1,8 @@ using LibGit2Sharp; using Newtonsoft.Json; using System; +using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -38,8 +40,52 @@ public static async Task GetMainBranchFromRepository(string repositoryNa return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())?.DefaultBranch; } - public static Task IsFileExists(string repoName, string branch, string filePath) => - IsFileExists($"https://raw.githubusercontent.com/{repoName}/{branch}/{filePath}"); + public static Task IsFileExists(string repoName, string branch, string filePath, string platformUrl = null) + { + if (!string.IsNullOrEmpty(platformUrl)) + { + var _fetchBaseUri = new Uri(platformUrl.Contains("http") ? platformUrl : "https://" + platformUrl); + var _fetchRelativeUri = new Uri(_fetchBaseUri, $"{repoName}"); + + var _fetchRepoDirectory = $"gitfetch/{repoName}/{branch}"; + + var _cloneOptions = new CloneOptions + { + Checkout = false, + IsBare = true, + BranchName = branch + }; + + _cloneOptions.FetchOptions.Prune = true; + + Repository.Clone(_fetchRelativeUri.ToString(), _fetchRepoDirectory, _cloneOptions); + var _fetchRepository = new Repository(_fetchRepoDirectory); + + var _fetchCommit = _fetchRepository.Head.Tip; + var _doesModFileExist = _fetchCommit["mod.yml"] != null; + + _fetchRepository.Dispose(); + + if (Directory.Exists(_fetchRepoDirectory)) + { + var _fetchAllFiles = Directory.GetFiles(_fetchRepoDirectory, "*", SearchOption.AllDirectories); + var _fetchAllDirectories = Directory.GetDirectories(_fetchRepoDirectory, "*", SearchOption.AllDirectories); + + foreach (var _fetchFile in _fetchAllFiles) + File.SetAttributes(_fetchFile, FileAttributes.Normal); + + foreach (string _fetchDirectory in _fetchAllDirectories) + File.SetAttributes(_fetchDirectory, FileAttributes.Normal); + + Directory.Delete(_fetchRepoDirectory, true); + } + + return Task.FromResult(_doesModFileExist); + } + + else + return IsFileExists($"https://raw.githubusercontent.com/{repoName}/{branch}/{filePath}"); + } public static async Task IsFileExists(string url) { diff --git a/OpenKh.Tools.ModsManager/ViewModels/DownloadableModViewModel.cs b/OpenKh.Tools.ModsManager/ViewModels/DownloadableModViewModel.cs index 12561eed0..8c6217d4f 100644 --- a/OpenKh.Tools.ModsManager/ViewModels/DownloadableModViewModel.cs +++ b/OpenKh.Tools.ModsManager/ViewModels/DownloadableModViewModel.cs @@ -71,7 +71,7 @@ private async void InstallMod() }); // Install mod with progress updates - await Task.Run(() => ModsService.InstallModFromGithub(Repo, + await Task.Run(() => ModsService.InstallModFromGit(Repo, progress => { Application.Current.Dispatcher.Invoke(() => progressWindow.ProgressText = progress); }, diff --git a/OpenKh.Tools.ModsManager/ViewModels/MainViewModel.cs b/OpenKh.Tools.ModsManager/ViewModels/MainViewModel.cs index fb7e01a87..64007e7ca 100644 --- a/OpenKh.Tools.ModsManager/ViewModels/MainViewModel.cs +++ b/OpenKh.Tools.ModsManager/ViewModels/MainViewModel.cs @@ -494,6 +494,7 @@ public MainViewModel() var name = view.RepositoryName; var isZipFile = view.IsZipFile; var isLuaFile = view.IsLuaFile; + var platformUrl = view.PlatformURL; var branchName = view.BranchName; progressWindow = Application.Current.Dispatcher.Invoke(() => { @@ -512,7 +513,7 @@ await ModsService.InstallMod(name, isZipFile, isLuaFile, progress => }, nProgress => { Application.Current.Dispatcher.Invoke(() => progressWindow.ProgressValue = nProgress); - }, branchName); + }, platformUrl, branchName); var repoName = name; if (!isZipFile && !isLuaFile) { diff --git a/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs b/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs index cc9aea002..cac2cd69b 100644 --- a/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs +++ b/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs @@ -1,3 +1,4 @@ +using LibGit2Sharp; using OpenKh.Common; using OpenKh.Tools.ModsManager.Models; using OpenKh.Tools.ModsManager.Services; @@ -7,6 +8,7 @@ using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Security.Policy; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; @@ -41,6 +43,14 @@ public ModViewModel(ModModel model, IChangeModEnableState changeModEnableState) { Author = Source[0..nameIndex]; Name = Source[(nameIndex + 1)..]; + + var _fetchRepository = new Repository(_model.Path); + var _fetchRemoteUrl = _fetchRepository.Network.Remotes.ElementAt(0).Url.TrimEnd('/'); + + SourceUrl = _fetchRemoteUrl; + ReportBugUrl = _fetchRemoteUrl += "/issues"; + + AuthorUrl = _fetchRemoteUrl.Substring(0, _fetchRemoteUrl.LastIndexOf('/') + 1); } else { @@ -175,9 +185,9 @@ public CollectionSettingsViewModel CollectionSelectedValue public string Name { get; } public string Author { get; } public string Source => _model.Name; - public string AuthorUrl => $"https://github.com/{Author}"; - public string SourceUrl => $"https://github.com/{Source}"; - public string ReportBugUrl => $"https://github.com/{Source}/issues"; + public string AuthorUrl { get; set; } + public string SourceUrl { get; set; } + public string ReportBugUrl { get; set; } public string FilesToPatch { get diff --git a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml index a439fa7fc..9ed403425 100644 --- a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml +++ b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml @@ -9,7 +9,7 @@ WindowStartupLocation="CenterScreen" ResizeMode="NoResize" FocusManager.FocusedElement="{Binding ElementName=txtSourceModUrl}" - Title="Install a new mod or Lua Script..." Height="160" Width="300" SizeToContent="Height" Background="{Binding ColorTheme.BackgroundColor}" Foreground="{Binding ColorTheme.TextColor}"> + Title="Install a new mod or Lua Script..." Height="238" Width="300" SizeToContent="Height" Background="{Binding ColorTheme.BackgroundColor}" Foreground="{Binding ColorTheme.TextColor}"> @@ -30,11 +30,26 @@ + Hosted Platform (optional) + + + + + + + + + Branch (optional) - - + + + + + + Install a Mod Archive or Lua Script diff --git a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml.cs b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml.cs index efeb0dbc9..5fcf36f91 100644 --- a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml.cs +++ b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml.cs @@ -18,6 +18,7 @@ public partial class InstallModView : Window public RelayCommand CloseCommand { get; } public string RepositoryName { get; set; } + public string PlatformURL { get; set; } public string BranchName { get; set; } public bool IsZipFile { get; private set; } public bool IsLuaFile { get; private set; } = false; From 8713f3e6c1ec238888fb004dc9c3e26d682a5c3d Mon Sep 17 00:00:00 2001 From: Topaz Whitelock <250328010.b@uni-prizren.com> Date: Sat, 1 Aug 2026 07:47:42 +0200 Subject: [PATCH 2/3] one single equal sign ruining my jibe --- OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs b/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs index cac2cd69b..d2b31f831 100644 --- a/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs +++ b/OpenKh.Tools.ModsManager/ViewModels/ModViewModel.cs @@ -48,7 +48,7 @@ public ModViewModel(ModModel model, IChangeModEnableState changeModEnableState) var _fetchRemoteUrl = _fetchRepository.Network.Remotes.ElementAt(0).Url.TrimEnd('/'); SourceUrl = _fetchRemoteUrl; - ReportBugUrl = _fetchRemoteUrl += "/issues"; + ReportBugUrl = _fetchRemoteUrl + "/issues"; AuthorUrl = _fetchRemoteUrl.Substring(0, _fetchRemoteUrl.LastIndexOf('/') + 1); } From 73bfb20cf258667d01dd97ffe497c8d73e75df7d Mon Sep 17 00:00:00 2001 From: Topaz Whitelock Date: Sat, 1 Aug 2026 20:30:58 +0200 Subject: [PATCH 3/3] Add the expander box. --- .../Views/InstallModView.xaml | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml index 9ed403425..d443ca61d 100644 --- a/OpenKh.Tools.ModsManager/Views/InstallModView.xaml +++ b/OpenKh.Tools.ModsManager/Views/InstallModView.xaml @@ -9,7 +9,7 @@ WindowStartupLocation="CenterScreen" ResizeMode="NoResize" FocusManager.FocusedElement="{Binding ElementName=txtSourceModUrl}" - Title="Install a new mod or Lua Script..." Height="238" Width="300" SizeToContent="Height" Background="{Binding ColorTheme.BackgroundColor}" Foreground="{Binding ColorTheme.TextColor}"> + Title="Install a new mod or Lua Script..." Height="183" Width="300" SizeToContent="Height" Background="{Binding ColorTheme.BackgroundColor}" Foreground="{Binding ColorTheme.TextColor}"> @@ -29,31 +29,35 @@ Foreground="Gray" Visibility="{Binding ElementName=txtSourceModUrl, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" IsHitTestVisible="False"/> - - Hosted Platform (optional) - - - - - - Install a Mod Archive or Lua Script + + + + + Hosted Platform (optional) + + + + + + - - + + - Branch (optional) - - - - - - Branch (optional) + + + + + + - - - - Install a Mod Archive or Lua Script - + + + +