Added game manifest model. Reworked settings to be a bit more universal across the extension. Made server URL configurable.

dashboard
Pat Hartl 2023-01-07 12:34:12 -06:00
parent cf326dd5ca
commit 787a983c03
10 changed files with 188 additions and 55 deletions

View File

@ -82,6 +82,9 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<Reference Include="YamlDotNet, Version=12.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
<HintPath>..\packages\YamlDotNet.12.3.1\lib\net45\YamlDotNet.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="InstallController.cs" /> <Compile Include="InstallController.cs" />

View File

@ -14,12 +14,12 @@ namespace LANCommander.Playnite.Extension
{ {
internal class LANCommanderClient internal class LANCommanderClient
{ {
private readonly RestClient Client; public readonly RestClient Client;
public AuthToken Token; public AuthToken Token;
public LANCommanderClient() public LANCommanderClient(string baseUrl)
{ {
Client = new RestClient("https://localhost:7087"); Client = new RestClient(baseUrl);
} }
private T PostRequest<T>(string route, object body) private T PostRequest<T>(string route, object body)
@ -89,6 +89,9 @@ namespace LANCommander.Playnite.Extension
var response = Client.Post<AuthResponse>(request); var response = Client.Post<AuthResponse>(request);
if (response.StatusCode != HttpStatusCode.OK)
throw new WebException(response.ErrorMessage);
return response.Data; return response.Data;
} }

View File

@ -1,19 +1,24 @@
using Playnite.SDK; using LANCommander.Models;
using Playnite.SDK;
using Playnite.SDK.Models; using Playnite.SDK.Models;
using Playnite.SDK.Plugins; using Playnite.SDK.Plugins;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using PN = Playnite;
namespace LANCommander.Playnite.Extension namespace LANCommander.Playnite.Extension
{ {
public class PlayniteLibraryPlugin : LibraryPlugin public class PlayniteLibraryPlugin : LibraryPlugin
{ {
public static readonly ILogger Logger = LogManager.GetLogger(); public static readonly ILogger Logger = LogManager.GetLogger();
private PlayniteSettingsViewModel Settings { get; set; } internal PlayniteSettingsViewModel Settings { get; set; }
internal LANCommanderClient LANCommander { get; set; } internal LANCommanderClient LANCommander { get; set; }
public override Guid Id { get; } = Guid.Parse("48e1bac7-e0a0-45d7-ba83-36f5e9e959fc"); public override Guid Id { get; } = Guid.Parse("48e1bac7-e0a0-45d7-ba83-36f5e9e959fc");
@ -22,41 +27,19 @@ namespace LANCommander.Playnite.Extension
public PlayniteLibraryPlugin(IPlayniteAPI api) : base(api) public PlayniteLibraryPlugin(IPlayniteAPI api) : base(api)
{ {
LANCommander = new LANCommanderClient();
Settings = new PlayniteSettingsViewModel(this);
Properties = new LibraryPluginProperties Properties = new LibraryPluginProperties
{ {
HasSettings = true, HasSettings = true,
}; };
LoadSettings();
} }
public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args) public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args)
{ {
try try
{ {
var token = new SDK.Models.AuthToken() var syncedGames = PlayniteApi.Database.Games;
{
AccessToken = Settings.AccessToken,
RefreshToken = Settings.RefreshToken,
};
LANCommander.Token = token;
var tokenIsValid = LANCommander.ValidateToken(token);
if (!tokenIsValid)
{
try
{
LANCommander.RefreshToken(token);
}
catch
{
ShowAuthenticationWindow();
}
}
LANCommander.Token = token;
var games = LANCommander var games = LANCommander
.GetGames() .GetGames()
@ -101,6 +84,52 @@ namespace LANCommander.Playnite.Extension
return new PlayniteSettingsView(this); return new PlayniteSettingsView(this);
} }
public void LoadSettings()
{
Settings = LoadPluginSettings<PlayniteSettingsViewModel>();
try
{
if (LANCommander == null)
LANCommander = new LANCommanderClient(Settings.ServerAddress);
LANCommander.Client.BaseUrl = new Uri(Settings.ServerAddress);
var token = new SDK.Models.AuthToken()
{
AccessToken = Settings.AccessToken,
RefreshToken = Settings.RefreshToken,
};
LANCommander.Token = token;
}
catch
{
}
}
public void SaveSettings()
{
SavePluginSettings(Settings);
if (LANCommander == null)
LANCommander = new LANCommanderClient(Settings.ServerAddress);
if (Settings.ServerAddress != LANCommander.Client.BaseUrl.ToString())
{
LANCommander.Client.BaseUrl = new Uri(Settings.ServerAddress);
var token = new SDK.Models.AuthToken()
{
AccessToken = Settings.AccessToken,
RefreshToken = Settings.RefreshToken,
};
LANCommander.Token = token;
}
}
public System.Windows.Window ShowAuthenticationWindow() public System.Windows.Window ShowAuthenticationWindow()
{ {
var window = PlayniteApi.Dialogs.CreateWindow(new WindowCreationOptions() var window = PlayniteApi.Dialogs.CreateWindow(new WindowCreationOptions()
@ -119,5 +148,44 @@ namespace LANCommander.Playnite.Extension
return window; return window;
} }
private GameMetadata ParseManifest(string installDirectory)
{
var manifestContents = File.ReadAllText(Path.Combine(installDirectory, "_manifest.yml"));
var deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.Build();
try
{
var manifest = deserializer.Deserialize<GameManifest>(manifestContents);
var metadata = new GameMetadata()
{
Name = manifest.Title,
SortingName = manifest.SortTitle,
Description = manifest.Description,
ReleaseDate = new ReleaseDate(manifest.ReleasedOn),
Version = manifest.Version,
GameActions = manifest.Actions.Select(a =>
{
return new PN.SDK.Models.GameAction()
{
Name = a.Name,
Arguments = a.Arguments,
Path = a.Path,
WorkingDir = a.WorkingDirectory,
IsPlayAction = a.IsPrimaryAction
};
}).ToList()
};
return metadata;
}
catch
{
throw new FileNotFoundException("The manifest file is invalid or corrupt.");
}
}
} }
} }

View File

@ -12,7 +12,7 @@ namespace LANCommander.Playnite.Extension
{ {
private readonly PlayniteLibraryPlugin Plugin; private readonly PlayniteLibraryPlugin Plugin;
public string ServerUrl { get; set; } = String.Empty; public string ServerAddress { get; set; } = String.Empty;
public string AccessToken { get; set; } = String.Empty; public string AccessToken { get; set; } = String.Empty;
public string RefreshToken { get; set; } = String.Empty; public string RefreshToken { get; set; } = String.Empty;
@ -25,14 +25,9 @@ namespace LANCommander.Playnite.Extension
{ {
Plugin = plugin; Plugin = plugin;
var savedSettings = Plugin.LoadPluginSettings<PlayniteSettingsViewModel>(); ServerAddress = Plugin.Settings.ServerAddress;
AccessToken = Plugin.Settings.AccessToken;
if (savedSettings != null) RefreshToken = Plugin.Settings.RefreshToken;
{
ServerUrl = savedSettings.ServerUrl;
AccessToken = savedSettings.AccessToken;
RefreshToken = savedSettings.RefreshToken;
}
} }
public void BeginEdit() public void BeginEdit()
@ -47,7 +42,9 @@ namespace LANCommander.Playnite.Extension
public void EndEdit() public void EndEdit()
{ {
// Plugin.SavePluginSettings(this); Plugin.Settings.ServerAddress = ServerAddress;
Plugin.SaveSettings();
} }
public bool VerifySettings(out List<string> errors) public bool VerifySettings(out List<string> errors)

View File

@ -27,23 +27,40 @@ namespace LANCommander.Playnite.Extension
InitializeComponent(); InitializeComponent();
var settings = new PlayniteSettingsViewModel(plugin); UpdateAuthenticationButtonVisibility();
}
if (Plugin.LANCommander.ValidateToken(new AuthToken() private void UpdateAuthenticationButtonVisibility()
{
try
{
if (Plugin.LANCommander.ValidateToken(new AuthToken()
{
AccessToken = Plugin.Settings.AccessToken,
RefreshToken = Plugin.Settings.RefreshToken,
}))
{
var authenticateButton = FindName("AuthenticateButton") as Button;
authenticateButton.Visibility = Visibility.Hidden;
}
}
catch
{ {
AccessToken = settings.AccessToken,
RefreshToken = settings.RefreshToken,
}))
{
var authenticateButton = FindName("AuthenticateButton") as Button;
authenticateButton.Visibility = Visibility.Hidden;
} }
} }
private void AuthenticateButton_Click(object sender, RoutedEventArgs e) private void AuthenticateButton_Click(object sender, RoutedEventArgs e)
{ {
Plugin.ShowAuthenticationWindow(); var authWindow = Plugin.ShowAuthenticationWindow();
authWindow.Closed += AuthWindow_Closed;
}
private void AuthWindow_Closed(object sender, EventArgs e)
{
UpdateAuthenticationButtonVisibility();
} }
} }
} }

View File

@ -8,6 +8,7 @@ namespace LANCommander.Playnite.Extension.ViewModels
{ {
internal class Authentication internal class Authentication
{ {
public string ServerAddress { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string Password { get; set; } public string Password { get; set; }
} }

View File

@ -13,6 +13,8 @@
</Style> </Style>
</d:DesignerProperties.DesignStyle> </d:DesignerProperties.DesignStyle>
<StackPanel Margin="20"> <StackPanel Margin="20">
<TextBlock Text="Server Address" />
<TextBox Name="ServerAddress" Text="{Binding ServerAddress}" KeyDown="TextBox_KeyDown" />
<TextBlock Text="Username"/> <TextBlock Text="Username"/>
<TextBox Name="Username" Text="{Binding UserName}" KeyDown="TextBox_KeyDown" /> <TextBox Name="Username" Text="{Binding UserName}" KeyDown="TextBox_KeyDown" />
<TextBlock Text="Password" /> <TextBlock Text="Password" />

View File

@ -21,12 +21,10 @@ namespace LANCommander.Playnite.Extension.Views
{ {
private PlayniteLibraryPlugin Plugin; private PlayniteLibraryPlugin Plugin;
private ViewModels.Authentication Context { get { return (ViewModels.Authentication)DataContext; } } private ViewModels.Authentication Context { get { return (ViewModels.Authentication)DataContext; } }
private PlayniteSettingsViewModel Settings { get; set; }
public Authentication(PlayniteLibraryPlugin plugin) public Authentication(PlayniteLibraryPlugin plugin)
{ {
Plugin = plugin; Plugin = plugin;
Settings = Plugin.GetSettings(false) as PlayniteSettingsViewModel;
InitializeComponent(); InitializeComponent();
} }
@ -56,16 +54,21 @@ namespace LANCommander.Playnite.Extension.Views
{ {
try try
{ {
if (Plugin.LANCommander == null)
Plugin.LANCommander = new LANCommanderClient(Context.ServerAddress);
else
Plugin.LANCommander.Client.BaseUrl = new Uri(Context.ServerAddress);
var response = Plugin.LANCommander.Authenticate(Context.UserName, Context.Password); var response = Plugin.LANCommander.Authenticate(Context.UserName, Context.Password);
Settings.AccessToken = response.AccessToken; Plugin.Settings.ServerAddress = Context.ServerAddress;
Settings.RefreshToken = response.RefreshToken; Plugin.Settings.AccessToken = response.AccessToken;
Plugin.Settings.RefreshToken = response.RefreshToken;
// Probably unneeded, but why not be more secure? // Probably unneeded, but why not be more secure?
Context.Password = String.Empty; Context.Password = String.Empty;
Plugin.SavePluginSettings(Settings); Plugin.SaveSettings();
//Plugin.Settings = Plugin.LoadPluginSettings<PlayniteSettingsViewModel>();
Window.GetWindow(this).Close(); Window.GetWindow(this).Close();
} }

View File

@ -12,4 +12,5 @@
<package id="System.Text.Json" version="5.0.1" targetFramework="net462" /> <package id="System.Text.Json" version="5.0.1" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" /> <package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" /> <package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
<package id="YamlDotNet" version="12.3.1" targetFramework="net462" />
</packages> </packages>

View File

@ -0,0 +1,38 @@
using System;
namespace LANCommander.Models
{
public class GameManifest
{
public string Title { get; set; }
public string SortTitle { get; set; }
public string Description { get; set; }
public DateTime ReleasedOn { get; set; }
public string[] Genre { get; set; }
public string[] Tags { get; set; }
public string[] Publishers { get; set; }
public string[] Developers { get; set; }
public string Version { get; set; }
public string Icon { get; set; }
public GameAction[] Actions { get; set; }
public bool Singleplayer { get; set; }
public MultiplayerInfo LocalMultiplayer { get; set; }
public MultiplayerInfo LanMultiplayer { get; set; }
public MultiplayerInfo OnlineMultiplayer { get; set; }
}
public class GameAction
{
public string Name { get; set; }
public string Arguments { get; set; }
public string Path { get; set; }
public string WorkingDirectory { get; set; }
public bool IsPrimaryAction { get; set; }
}
public class MultiplayerInfo
{
public int MinPlayers { get; set; }
public int MaxPlayers { get; set; }
}
}