Skip to content

Commit

Permalink
Merge pull request #48 from KrystianLesniak/develop
Browse files Browse the repository at this point in the history
Release: 1.8.0
  • Loading branch information
KrystianLesniak committed Jan 14, 2024
2 parents f76b1ed + 4f65a93 commit 81d9435
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ GamesLauncher is a plugin for [Flow launcher](https://github.com/Flow-Launcher/F
* Steam
* Epic Games Launcher
* Xbox
* EA app
* Ubisoft Connect
* Amazon Games
* [Custom Shortcuts](#custom-shortcuts)
Expand Down
1 change: 1 addition & 0 deletions src/GamesLauncher.Common/Settings/MainSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public class MainSettings
public bool SynchronizeXbox { get; set; } = true;
public bool SynchronizeAmazon { get; set; } = true;
public bool SynchronizeUbisoft { get; set; } = true;
public bool SynchronizeEaApp { get; set; } = true;
}
}
5 changes: 4 additions & 1 deletion src/GamesLauncher.Platforms/GamesLauncher.Platforms.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
Expand Down Expand Up @@ -28,6 +28,9 @@
<None Update="Icons\amazon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Icons\ea.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Icons\epic.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
Binary file added src/GamesLauncher.Platforms/Icons/ea.ico
Binary file not shown.
6 changes: 5 additions & 1 deletion src/GamesLauncher.Platforms/PlatformsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using GamesLauncher.Platforms.SyncEngines;
using GamesLauncher.Platforms.SyncEngines.Amazon;
using GamesLauncher.Platforms.SyncEngines.Common.Interfaces;
using GamesLauncher.Platforms.SyncEngines.EaApp;
using GamesLauncher.Platforms.SyncEngines.Epic;
using GamesLauncher.Platforms.SyncEngines.Steam;
using GamesLauncher.Platforms.SyncEngines.Ubisoft;
Expand Down Expand Up @@ -36,7 +37,7 @@ await Parallel.ForEachAsync(Engines, async (engine, ct) =>
{
await engine.SynchronizeGames();
}
catch(Exception ex)
catch (Exception ex)
{
//TODO: Think about shortening an overly long error message title
publicApi.ShowMsgError($"GamesLauncher: {engine.PlatformName} failed to synchronize", "Please submit your issue with logs at plugin GitHub page.");
Expand Down Expand Up @@ -70,6 +71,9 @@ private IEnumerable<ISyncEngine> InitializeEngines(MainSettings settings)
if (settings.SynchronizeAmazon)
engines.Add(new AmazonSyncEngine(publicApi));

if (settings.SynchronizeEaApp)
engines.Add(new EaAppSyncEngine(publicApi));

engines.Add(new ShortcutsSyncEngine(publicApi));

return engines;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ static void SearchPrograms(RegistryHive hive, RegistryView view, ConcurrentBag<U

programs.Add(new UninstallProgram()
{
DisplayIcon = prog.GetValue("DisplayIcon")?.ToString(),
DisplayIconPath = prog.GetValue("DisplayIcon")?.ToString(),
DisplayName = prog.GetValue("DisplayName")?.ToString() ?? string.Empty,
UninstallCommand = prog.GetValue("UninstallString")?.ToString(),
InstallLocation = prog.GetValue("InstallLocation")?.ToString() ?? string.Empty,
SubKeyName = programUninstallSubKeyName
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,21 @@ internal class UninstallProgram
{
public string DisplayName { get; internal set; } = string.Empty;
public string SubKeyName { get; internal set; } = string.Empty;
public string? DisplayIcon { get; internal set; }

public string? DisplayIconPath
{
get
{
return displayIconPath is null
? displayIconPath
: Path.Combine(displayIconPath.Replace("\"", string.Empty).Trim('\\'));
}
internal set => displayIconPath = value;
}
private string? displayIconPath;

public string? UninstallCommand { get; internal set; }
public string InstallLocation { get; internal set; } = string.Empty;

}
}
121 changes: 121 additions & 0 deletions src/GamesLauncher.Platforms/SyncEngines/EaApp/EaAppSyncEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Flow.Launcher.Plugin;
using GamesLauncher.Platforms.SyncEngines.Common.ControlPanelUninstall;
using GamesLauncher.Platforms.SyncEngines.Common.ControlPanelUninstall.Models;
using GamesLauncher.Platforms.SyncEngines.Common.Interfaces;
using GamesLauncher.Platforms.SyncEngines.EaApp.Models;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;

namespace GamesLauncher.Platforms.SyncEngines.EaApp
{
internal partial class EaAppSyncEngine : ISyncEngine
{
public string PlatformName => "EA app";
public IEnumerable<Game> SynchronizedGames { get; private set; } = Array.Empty<Game>();

private readonly string GameInstallerDataSubdirectory = Path.Combine("__Installer", "installerdata.xml");

private readonly IPublicAPI publicApi;

public EaAppSyncEngine(IPublicAPI publicApi)
{
this.publicApi = publicApi;
}

public async Task SynchronizeGames()
{
var eaAppUninstallPrograms = (await ControlPanelUninstall.GetPrograms())
.Where(x => x.UninstallCommand != null && x.UninstallCommand.Contains("EAInstaller") && x.UninstallCommand.Contains("Cleanup.exe"));

if (!eaAppUninstallPrograms.Any())
return;

var syncedGames = new List<Game>();

foreach (var eaUninstallProgram in eaAppUninstallPrograms)
{
var installerDataXmlPath = Path.Combine(eaUninstallProgram.InstallLocation, GameInstallerDataSubdirectory);

if (!File.Exists(installerDataXmlPath)) continue;

var gameExePath = GetGameExePathFromInstallerData(eaUninstallProgram.InstallLocation, installerDataXmlPath)
?? GetGameExePathFromUninstallProgram(eaUninstallProgram);

if (gameExePath is null) continue;

syncedGames.Add(new Game(
title: eaUninstallProgram.DisplayName,
platform: PlatformName,
runTask: async () =>
{
var directory = Path.GetDirectoryName(gameExePath);
var fileExe = Path.GetFileName(gameExePath);
publicApi.ShellRun($"cd /d \"{directory}\" && start \"\" \"{fileExe}\"");
await Task.CompletedTask;
},
iconPath: eaUninstallProgram.DisplayIconPath ?? Path.Combine("Icons", "ea.ico"),
uninstallAction: GetUninstallAction(eaUninstallProgram)
));
}

SynchronizedGames = syncedGames;
}

private static string? GetGameExePathFromInstallerData(string installLocation, string installerDataXmlPath)
{
var xmlSerializer = new XmlSerializer(typeof(InstallerDataXml));
using var xmlReader = XmlReader.Create(installerDataXmlPath);

if (!xmlSerializer.CanDeserialize(xmlReader)) return null;
if (xmlSerializer.Deserialize(xmlReader) is not InstallerDataXml installerData) return null;

var launcherData = installerData.Runtime?.Launchers.FirstOrDefault(x => x.Trial == false);

if (launcherData is null) return null; //TODO: Test how trials behaves

var gameExe = RegistryKeyEaPaths().Replace(launcherData.FilePath, string.Empty);
var gameExePath = Path.Combine(installLocation, gameExe);

if (!File.Exists(gameExePath)) return null;

return gameExePath;
}

private static string? GetGameExePathFromUninstallProgram(UninstallProgram eaUninstallProgram)
{
if (Path.GetExtension(eaUninstallProgram.DisplayIconPath) == ".exe")
return eaUninstallProgram.DisplayIconPath;

return null;
}

private UninstallAction? GetUninstallAction(UninstallProgram eaUninstallProgram)
{
var uninstallCommand = eaUninstallProgram.UninstallCommand;
var subKeyName = eaUninstallProgram.SubKeyName;

if (uninstallCommand == null) return null;

return new UninstallAction(async () =>
{
publicApi.ShellRun(uninstallCommand);
for (int i = 0; i < 12; i++)
{
var programs = await ControlPanelUninstall.GetPrograms();
if (programs.Any(x => x.SubKeyName.Equals(subKeyName)) == false)
break;
await Task.Delay(TimeSpan.FromSeconds(5));
}
await SynchronizeGames();
});
}

[GeneratedRegex("\\[.*?\\]")]
private static partial Regex RegistryKeyEaPaths();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Xml.Serialization;

namespace GamesLauncher.Platforms.SyncEngines.EaApp.Models
{
[XmlRoot("DiPManifest")]
public class InstallerDataXml
{
[XmlElement("runtime")]
public Runtime? Runtime { get; set; }
}

public class Runtime
{
[XmlElement("launcher")]
public List<Launcher> Launchers { get; set; } = new List<Launcher>();
}

public class Launcher
{
[XmlElement("filePath")]
public string FilePath { get; set; } = string.Empty;

[XmlElement("trial")]
public bool Trial { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task SynchronizeGames()
title: ubiUninstallProgram.DisplayName,
platform: PlatformName,
runTask: GetGameRunTask(ubiUninstallProgram),
iconPath: ubiUninstallProgram.DisplayIcon ?? Path.Combine("Icons", "ubisoft.ico"),
iconPath: ubiUninstallProgram.DisplayIconPath ?? Path.Combine("Icons", "ubisoft.ico"),
uninstallAction: GetUninstallAction(ubiUninstallProgram)
));
}
Expand Down
17 changes: 12 additions & 5 deletions src/GamesLauncher/Views/SettingsView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Expand All @@ -45,20 +46,26 @@
HorizontalAlignment="Left"
Content="Xbox" />
<CheckBox
x:Name="SynchronizeUbisoft"
x:Name="SynchronizeEaApp"
Grid.Row="4"
Margin="10,5,5,5"
HorizontalAlignment="Left"
Content="EA app" />
<CheckBox
x:Name="SynchronizeUbisoft"
Grid.Row="5"
Margin="10,5,5,5"
HorizontalAlignment="Left"
Content="Ubisoft Connect" />
<CheckBox
x:Name="SynchronizeAmazon"
Grid.Row="5"
Grid.Row="6"
Margin="10,5,5,5"
HorizontalAlignment="Left"
Content="Amazon Games" />
<Button
Click="BtnOpenCustomShortcutsDirectory_Click"
Grid.Row="6"
Grid.Row="7"
Margin="10,5,5,5"
Padding="20,10,20,10"
HorizontalAlignment="Left"
Expand All @@ -69,7 +76,7 @@
</Button>
<Button
Click="BtnShowHiddenGames_Click"
Grid.Row="7"
Grid.Row="8"
Margin="10,5,5,5"
Padding="20,10,20,10"
HorizontalAlignment="Left"
Expand All @@ -78,7 +85,7 @@
<StackPanel
Name="HiddenGamesStackPanel"
Visibility="Collapsed"
Grid.Row="8">
Grid.Row="9">
<ListView
Name="HiddenGames"
Height="auto"
Expand Down
10 changes: 10 additions & 0 deletions src/GamesLauncher/Views/SettingsView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ private void SettingsView_OnLoaded(object sender, RoutedEventArgs re)
SynchronizeSteam.IsChecked = _settings.SynchronizeSteam;
SyncrhonizeEpic.IsChecked = _settings.SynchronizeEpicGamesStore;
SynchronizeXbox.IsChecked = _settings.SynchronizeXbox;
SynchronizeEaApp.IsChecked = _settings.SynchronizeEaApp;
SynchronizeUbisoft.IsChecked = _settings.SynchronizeUbisoft;
SynchronizeAmazon.IsChecked = _settings.SynchronizeAmazon;

Expand Down Expand Up @@ -60,6 +61,15 @@ private void SettingsView_OnLoaded(object sender, RoutedEventArgs re)
_settings.SynchronizeXbox = false;
};

SynchronizeEaApp.Checked += (o, e) =>
{
_settings.SynchronizeEaApp = true;
};
SynchronizeEaApp.Unchecked += (o, e) =>
{
_settings.SynchronizeEaApp = false;
};

SynchronizeUbisoft.Checked += (o, e) =>
{
_settings.SynchronizeUbisoft = true;
Expand Down
2 changes: 1 addition & 1 deletion src/GamesLauncher/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"Name": "GamesLauncher",
"Description": "Search and launch games from multiple platforms like Steam, Epic Games, Xbox etc.",
"Author": "KrystianLesniak",
"Version": "1.7.2",
"Version": "1.8.0",
"Language": "csharp",
"Website": "https://github.com/KrystianLesniak/Flow.Launcher.Plugin.GamesLauncher",
"IcoPath": "icon.png",
Expand Down

0 comments on commit 81d9435

Please sign in to comment.