Skip to content

Commit

Permalink
Merge pull request #10 from KrystianLesniak/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
KrystianLesniak authored Aug 23, 2023
2 parents 59d8077 + f8d7b5a commit c9d5801
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 50 deletions.
8 changes: 8 additions & 0 deletions Flow.Launcher.Plugin.GamesLauncher/Data/LastPlayedGames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Collections.Generic;

namespace Flow.Launcher.Plugin.GamesLauncher.Data
{
public class LastPlayedGames : List<string>
{
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Flow.Launcher.Plugin.GamesLauncher
namespace Flow.Launcher.Plugin.GamesLauncher.Data
{
public class Settings
{
Expand Down
71 changes: 71 additions & 0 deletions Flow.Launcher.Plugin.GamesLauncher/Handlers/GameHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Flow.Launcher.Plugin.GamesLauncher.Data;
using System;
using System.Threading.Tasks;

namespace Flow.Launcher.Plugin.GamesLauncher.Handlers
{
internal class GameHandler
{
private readonly IPublicAPI publicApi;

private readonly LastPlayedGames lastPlayedGames;

public GameHandler(LastPlayedGames lastPlayedGames, IPublicAPI publicApi)
{
this.publicApi = publicApi;
this.lastPlayedGames = lastPlayedGames;
}

public Func<ActionContext, ValueTask<bool>> GetGameRunTaskByUri(string platform, string gameTitle, string uriString)
{
return (context) =>
{
publicApi.OpenAppUri(new Uri(uriString));
AddLaunchedGameToLastPlayed(platform, gameTitle);
return ValueTask.FromResult(true);
};
}

public Func<ActionContext, ValueTask<bool>> GetGameRunTaskByShell(string platform, string gameTitle, string cmd, string shell = "explorer.exe")
{
return (context) =>
{
publicApi.ShellRun(cmd, shell);
AddLaunchedGameToLastPlayed(platform, gameTitle);
return ValueTask.FromResult(true);
};
}

private void AddLaunchedGameToLastPlayed(string platform, string gameTitle)
{
var gameId = PrepareGameIdentifier(platform, gameTitle);

if (lastPlayedGames.Contains(gameId))
{
lastPlayedGames.Remove(gameId);
lastPlayedGames.Add(gameId);
}
else
{
lastPlayedGames.Add(gameId);

if (lastPlayedGames.Count > 10)
lastPlayedGames.RemoveAt(0);
}
}

public int GetGameResultScoreByOrder(string platform, string gameTitle)
{
var gameId = PrepareGameIdentifier(platform, gameTitle);

var index = lastPlayedGames.LastIndexOf(gameId);

return (++index) * 100;
}

private static string PrepareGameIdentifier(string platform, string gameTitle)
=> $"{platform}_{gameTitle}";
}
}
24 changes: 19 additions & 5 deletions Flow.Launcher.Plugin.GamesLauncher/Main.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Flow.Launcher.Plugin.GamesLauncher.Data;
using Flow.Launcher.Plugin.GamesLauncher.Handlers;
using Flow.Launcher.Plugin.GamesLauncher.Models;
using Flow.Launcher.Plugin.GamesLauncher.SyncEngines;
using Flow.Launcher.Plugin.GamesLauncher.SyncEngines.EpicSyncEngine;
Expand All @@ -18,6 +20,7 @@ public class GamesLauncher : IAsyncPlugin, ISettingProvider, IAsyncReloadable
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private PluginInitContext _context;
private Settings _settings;
private GameHandler _gameHandler;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.


Expand All @@ -27,6 +30,7 @@ public async Task InitAsync(PluginInitContext context)
{
_context = context;
_settings = context.API.LoadSettingJsonStorage<Settings>();
_gameHandler = new GameHandler(context.API.LoadSettingJsonStorage<LastPlayedGames>(), context.API);

await SynchronizeLibrary();
}
Expand All @@ -51,15 +55,25 @@ public Control CreateSettingPanel()
}
private Result MapGameToResult(Game game, string search)
{
return new Result
var result = new Result
{
Title = game.Title,
AsyncAction = game.RunTask,
IcoPath = game.IconPath,
Icon = game.IconDelegate,
SubTitle = game.Platform,
Score = string.IsNullOrWhiteSpace(search) ? 0 : _context.API.FuzzySearch(search, game.Title).Score
};

if (string.IsNullOrWhiteSpace(search)) //When there is no search query display 10 last played games
{
result.Score = _gameHandler.GetGameResultScoreByOrder(game.Platform, game.Title);
}
else
{
result.Score = _context.API.FuzzySearch(search, game.Title).Score;
}

return result;
}

private async Task SynchronizeLibrary()
Expand All @@ -74,13 +88,13 @@ private IEnumerable<ISyncEngine> InitializeEngines()
var engines = new List<ISyncEngine>();

if (_settings.SynchronizeXbox)
engines.Add(new XboxSyncEngine(_context.API));
engines.Add(new XboxSyncEngine(_gameHandler));

if (_settings.SynchronizeEpicGamesStore)
engines.Add(new EpicSyncEngine(_context.API));
engines.Add(new EpicSyncEngine(_gameHandler));

if (_settings.SynchronizeSteam)
engines.Add(new SteamSyncEngine(_context.API));
engines.Add(new SteamSyncEngine(_gameHandler));

return engines;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Flow.Launcher.Plugin.GamesLauncher.Models;
using Flow.Launcher.Plugin.GamesLauncher.Handlers;
using Flow.Launcher.Plugin.GamesLauncher.Models;
using Flow.Launcher.Plugin.GamesLauncher.SyncEngines.EpicSyncEngine.Models;
using Microsoft.Win32;
using System;
Expand All @@ -14,12 +15,11 @@ internal class EpicSyncEngine : ISyncEngine
{
public string PlatformName => "Epic Games Launcher";

private readonly GameHandler gameHandler;

private readonly IPublicAPI publicApi;

public EpicSyncEngine(IPublicAPI publicApi)
public EpicSyncEngine(GameHandler gameHandler)
{
this.publicApi = publicApi;
this.gameHandler = gameHandler;
}

public async IAsyncEnumerable<Game> GetGames()
Expand All @@ -28,16 +28,11 @@ public async IAsyncEnumerable<Game> GetGames()

foreach (var epicGame in epicGames)
{
var uriLaunchString = PrepareLaunchUri(epicGame.CatalogNamespace, epicGame.CatalogItemId, epicGame.AppName);

yield return new Game(
Title: epicGame.DisplayName,
RunTask: (context) =>
{
var uriString = PrepareLaunchUri(epicGame.CatalogNamespace, epicGame.CatalogItemId, epicGame.AppName);
publicApi.OpenAppUri(new Uri(uriString));
return ValueTask.FromResult(true);
},
RunTask: gameHandler.GetGameRunTaskByUri(PlatformName, epicGame.DisplayName, uriLaunchString),
IconPath: PrepareIconPath(epicGame),
Platform: PlatformName,
IconDelegate: null
Expand Down Expand Up @@ -69,7 +64,7 @@ private static async Task<IEnumerable<EpicGame>> GetEpicGamesFromMetadata()
return epicGames;
}

private string PrepareIconPath(EpicGame epicGame)
private static string PrepareIconPath(EpicGame epicGame)
{
if (epicGame.InstallLocation != null && epicGame.LaunchExecutable != null)
{
Expand Down
22 changes: 9 additions & 13 deletions Flow.Launcher.Plugin.GamesLauncher/SyncEngines/SteamSyncEngine.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Flow.Launcher.Plugin.GamesLauncher.Models;
using Flow.Launcher.Plugin.GamesLauncher.Handlers;
using Flow.Launcher.Plugin.GamesLauncher.Models;
using GameFinder.Common;
using GameFinder.RegistryUtils;
using GameFinder.StoreHandlers.Steam;
using NexusMods.Paths;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -17,11 +17,12 @@ internal class SteamSyncEngine : ISyncEngine


private readonly SteamHandler handler = new(FileSystem.Shared, WindowsRegistry.Shared);
private readonly IPublicAPI publicApi;
private const string steamLaunchUri = "steam://launch/";
public SteamSyncEngine(IPublicAPI publicApi)

private readonly GameHandler gameHandler;
public SteamSyncEngine(GameHandler gameHandler)
{
this.publicApi = publicApi;
this.gameHandler = gameHandler;
}

public async IAsyncEnumerable<Game> GetGames()
Expand All @@ -40,16 +41,11 @@ public async IAsyncEnumerable<Game> GetGames()

private Game MapSteamGameToGame(SteamGame steamGame)
{
var uriString = steamLaunchUri + steamGame.AppId.ToString().Trim();

return new Game(
Title: steamGame.Name,
RunTask: (context) =>
{
var uriString = steamLaunchUri + steamGame.AppId.ToString().Trim();
publicApi.OpenAppUri(new Uri(uriString));
return ValueTask.FromResult(true);
},
RunTask: gameHandler.GetGameRunTaskByUri(PlatformName, steamGame.Name, uriString),
IconPath: GetIconPath(steamGame),
Platform: PlatformName,
IconDelegate: null
Expand Down
26 changes: 13 additions & 13 deletions Flow.Launcher.Plugin.GamesLauncher/SyncEngines/XboxSyncEngine.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Flow.Launcher.Plugin.GamesLauncher.Models;
using Flow.Launcher.Plugin.GamesLauncher.Handlers;
using Flow.Launcher.Plugin.GamesLauncher.Models;
using GameFinder.StoreHandlers.Xbox;
using Microsoft.WindowsAPICodePack.Shell;
using NexusMods.Paths;
Expand All @@ -14,13 +15,13 @@ internal class XboxSyncEngine : ISyncEngine
public string PlatformName => "Xbox";

private readonly XboxHandler handler = new(FileSystem.Shared);

private readonly Guid FODLERID_AppsFolder = new("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
private readonly IPublicAPI publicApi;

public XboxSyncEngine(IPublicAPI publicApi)
private readonly GameHandler gameHandler;

public XboxSyncEngine(GameHandler lastPlayedHandler)
{
this.publicApi = publicApi;
this.gameHandler = lastPlayedHandler;
}

public async IAsyncEnumerable<Game> GetGames()
Expand All @@ -34,18 +35,17 @@ public async IAsyncEnumerable<Game> GetGames()

foreach (var game in games)
{
var shellGame = appsFolder.FirstOrDefault(x => x.Name == game.DisplayName);
var gameTitle = game.DisplayName;

var shellGame = appsFolder.FirstOrDefault(x => x.Name == gameTitle);
if (shellGame != null)
{
var cmd = $"shell:appsFolder\\{shellGame.ParsingName}";

yield return new Game(
Title: game.DisplayName,
Title: gameTitle,
Platform: PlatformName,
RunTask: (context) =>
{
publicApi.ShellRun($"shell:appsFolder\\{shellGame.ParsingName}", "explorer.exe");
return ValueTask.FromResult(true);
},
RunTask: gameHandler.GetGameRunTaskByShell(PlatformName, gameTitle, cmd),
IconPath: null,
IconDelegate: delegate ()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Windows;
using Flow.Launcher.Plugin.GamesLauncher.Data;
using System.Windows;
using System.Windows.Controls;

namespace Flow.Launcher.Plugin.GamesLauncher.Views
Expand Down
Binary file modified Flow.Launcher.Plugin.GamesLauncher/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<img src="Flow.Launcher.Plugin.GamesLauncher/icon.png" width="32" height="32"> GamesLauncher - Flow Launcher Plugin
==================
<p align="center">
<img src="docs/logo.svg" height="40%" width="40%">
</p>

***

GamesLauncher is a plugin for [Flow launcher](https://github.com/Flow-Launcher/Flow.Launcher) that simplifies the process of searching for and launching games from multiple libraries. It provides quick and convenient access to your favorite games across various platforms, including Steam, Epic Games, Xbox, and more libraries to come.

![Capture](docs/capture.gif)

![Downloads](https://img.shields.io/github/downloads/KrystianLesniak/Flow.Launcher.Plugin.GamesLauncher/total)

### Supported platforms
* Steam
Expand All @@ -19,13 +24,18 @@ In Flow Launcher, use the plugin store to find "GamesLauncher" or type:
## Usage
Just type `gl` command.

Get the last games started:

gl

Search for a games:

gl <game-title-to-seek>

### Settings
You can disable specific platforms via settings menu.

![Setting](docs/settings.png)
<img src="docs/settings.png" height="40%" width="40%">

### Update library
If you have (un)installed a game, you can update the plugin without restarting Flow Launcher by using the `Reload Plugin Data` command.
Expand Down
6 changes: 6 additions & 0 deletions docs/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c9d5801

Please sign in to comment.