diff --git a/LANCommander.Playnite.Extension/InstallController.cs b/LANCommander.Playnite.Extension/InstallController.cs index 37e163a..d563226 100644 --- a/LANCommander.Playnite.Extension/InstallController.cs +++ b/LANCommander.Playnite.Extension/InstallController.cs @@ -11,6 +11,8 @@ using System.Threading; using System.Threading.Tasks; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Core; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; namespace LANCommander.PlaynitePlugin { @@ -39,6 +41,8 @@ namespace LANCommander.PlaynitePlugin InstallDirectory = installDirectory }; + File.WriteAllText(Path.Combine(installDirectory, "_manifest.yml"), GetManifest(gameId)); + InvokeOnInstalled(new GameInstalledEventArgs(installInfo)); Plugin.UpdateGamesFromManifest(); @@ -48,16 +52,14 @@ namespace LANCommander.PlaynitePlugin { string tempFile = String.Empty; - var archive = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault(); - - if (archive != null) + if (game != null) { Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress => { progress.ProgressMaxValue = 100; progress.CurrentProgressValue = 0; - var destination = Plugin.LANCommander.DownloadArchive(archive.Id, (changed) => + var destination = Plugin.LANCommander.DownloadGame(game.Id, (changed) => { progress.CurrentProgressValue = changed.ProgressPercentage; }, (complete) => @@ -82,7 +84,7 @@ namespace LANCommander.PlaynitePlugin return tempFile; } else - throw new Exception("Game failed to download"); + throw new Exception("Game failed to download!"); } private string Extract(LANCommander.SDK.Models.Game game, string archivePath) @@ -142,5 +144,18 @@ namespace LANCommander.PlaynitePlugin return destination; } + + private string GetManifest(Guid gameId) + { + var manifest = Plugin.LANCommander.GetGameManifest(gameId); + + var serializer = new SerializerBuilder() + .WithNamingConvention(PascalCaseNamingConvention.Instance) + .Build(); + + var yaml = serializer.Serialize(manifest); + + return yaml; + } } } diff --git a/LANCommander.Playnite.Extension/LANCommanderClient.cs b/LANCommander.Playnite.Extension/LANCommanderClient.cs index f69ddb2..8019039 100644 --- a/LANCommander.Playnite.Extension/LANCommanderClient.cs +++ b/LANCommander.Playnite.Extension/LANCommanderClient.cs @@ -1,4 +1,5 @@ -using LANCommander.SDK.Models; +using LANCommander.SDK; +using LANCommander.SDK.Models; using RestSharp; using RestSharp.Extensions; using System; @@ -115,6 +116,16 @@ namespace LANCommander.PlaynitePlugin return GetRequest($"/api/Games/{id}"); } + public GameManifest GetGameManifest(Guid id) + { + return GetRequest($"/api/Games/{id}/Manifest"); + } + + public string DownloadGame(Guid id, Action progressHandler, Action completeHandler) + { + return DownloadRequest($"/api/Games/{id}/Download", progressHandler, completeHandler); + } + public string DownloadArchive(Guid id, Action progressHandler, Action completeHandler) { return DownloadRequest($"api/Archives/Download/{id}", progressHandler, completeHandler); diff --git a/LANCommander.Playnite.Extension/PlayniteLibraryPlugin.cs b/LANCommander.Playnite.Extension/PlayniteLibraryPlugin.cs index 1f53f1b..758c0c2 100644 --- a/LANCommander.Playnite.Extension/PlayniteLibraryPlugin.cs +++ b/LANCommander.Playnite.Extension/PlayniteLibraryPlugin.cs @@ -1,4 +1,5 @@ -using LANCommander.Models; +using LANCommander.PlaynitePlugin.Extensions; +using LANCommander.SDK; using Playnite.SDK; using Playnite.SDK.Models; using Playnite.SDK.Plugins; @@ -48,11 +49,11 @@ namespace LANCommander.PlaynitePlugin try { var games = LANCommander - .GetGames() - .Where(g => g.Archives != null && g.Archives.Count() > 0); + .GetGames(); foreach (var game in games) { + var manifest = LANCommander.GetGameManifest(game.Id); var existingGame = PlayniteApi.Database.Games.FirstOrDefault(g => g.GameId == game.Id.ToString() && g.PluginId == Id && g.IsInstalled); var iconUri = new Uri(new Uri(Settings.ServerAddress), $"Games/GetIcon/{game.Id}"); @@ -60,15 +61,42 @@ namespace LANCommander.PlaynitePlugin var metadata = new GameMetadata() { IsInstalled = existingGame != null, - Name = game.Title, - SortingName = game.SortTitle, - Description = game.Description, + Name = manifest.Title, + SortingName = manifest.SortTitle, + Description = manifest.Description, GameId = game.Id.ToString(), - ReleaseDate = new ReleaseDate(game.ReleasedOn), - Version = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Version, - Icon = new MetadataFile(iconUri.ToString()) + ReleaseDate = new ReleaseDate(manifest.ReleasedOn), + //Version = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Version, + Icon = new MetadataFile(iconUri.ToString()), + Genres = new HashSet() }; + if (manifest.Genre != null && manifest.Genre.Count() > 0) + metadata.Genres = new HashSet(manifest.Genre.Select(g => new MetadataNameProperty(g))); + + if (manifest.Developers != null && manifest.Developers.Count() > 0) + metadata.Developers = new HashSet(manifest.Developers.Select(d => new MetadataNameProperty(d))); + + if (manifest.Publishers != null && manifest.Publishers.Count() > 0) + metadata.Publishers = new HashSet(manifest.Publishers.Select(p => new MetadataNameProperty(p))); + + if (manifest.Tags != null && manifest.Tags.Count() > 0) + metadata.Tags = new HashSet(manifest.Tags.Select(t => new MetadataNameProperty(t))); + + metadata.Features = new HashSet(); + + if (manifest.Singleplayer) + metadata.Features.Add(new MetadataNameProperty("Singleplayer")); + + if (manifest.LocalMultiplayer != null) + metadata.Features.Add(new MetadataNameProperty($"Local Multiplayer {manifest.LocalMultiplayer.GetPlayerCount()}".Trim())); + + if (manifest.LanMultiplayer != null) + metadata.Features.Add(new MetadataNameProperty($"LAN Multiplayer {manifest.LanMultiplayer.GetPlayerCount()}".Trim())); + + if (manifest.OnlineMultiplayer != null) + metadata.Features.Add(new MetadataNameProperty($"Online Multiplayer {manifest.OnlineMultiplayer.GetPlayerCount()}".Trim())); + gameMetadata.Add(metadata); }; } diff --git a/LANCommander.SDK/Models/GameManifest.cs b/LANCommander.SDK/Models/GameManifest.cs index ad127d8..6f705fc 100644 --- a/LANCommander.SDK/Models/GameManifest.cs +++ b/LANCommander.SDK/Models/GameManifest.cs @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; -namespace LANCommander.Models +namespace LANCommander.SDK { public class GameManifest { @@ -8,17 +9,19 @@ namespace LANCommander.Models 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 IEnumerable Genre { get; set; } + public IEnumerable Tags { get; set; } + public IEnumerable Publishers { get; set; } + public IEnumerable Developers { get; set; } public string Version { get; set; } public string Icon { get; set; } - public GameAction[] Actions { get; set; } + public IEnumerable Actions { get; set; } public bool Singleplayer { get; set; } public MultiplayerInfo LocalMultiplayer { get; set; } public MultiplayerInfo LanMultiplayer { get; set; } public MultiplayerInfo OnlineMultiplayer { get; set; } + + public GameManifest() { } } public class GameAction diff --git a/LANCommander/Controllers/Api/GamesController.cs b/LANCommander/Controllers/Api/GamesController.cs index 8242c13..758043f 100644 --- a/LANCommander/Controllers/Api/GamesController.cs +++ b/LANCommander/Controllers/Api/GamesController.cs @@ -1,5 +1,8 @@ using LANCommander.Data; using LANCommander.Data.Models; +using LANCommander.Extensions; +using LANCommander.Models; +using LANCommander.SDK; using LANCommander.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -30,5 +33,36 @@ namespace LANCommander.Controllers.Api { return await GameService.Get(id); } + + + + [HttpGet("{id}/Manifest")] + public async Task GetManifest(Guid id) + { + var manifest = await GameService.GetManifest(id); + + return manifest; + } + + [HttpGet("{id}/Download")] + public async Task Download(Guid id) + { + var game = await GameService.Get(id); + + if (game == null) + return NotFound(); + + if (game.Archives == null || game.Archives.Count == 0) + return NotFound(); + + var archive = game.Archives.OrderByDescending(a => a.CreatedOn).First(); + + var filename = Path.Combine("Upload", archive.ObjectKey); + + if (!System.IO.File.Exists(filename)) + return NotFound(); + + return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{game.Title.SanitizeFilename()}.zip"); + } } } diff --git a/LANCommander/Controllers/ArchivesController.cs b/LANCommander/Controllers/ArchivesController.cs index ad1eca0..0acbb17 100644 --- a/LANCommander/Controllers/ArchivesController.cs +++ b/LANCommander/Controllers/ArchivesController.cs @@ -2,6 +2,7 @@ using LANCommander.Data.Models; using LANCommander.Extensions; using LANCommander.Models; +using LANCommander.SDK; using LANCommander.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/LANCommander/Models/GameManifest.cs b/LANCommander/Models/GameManifest.cs deleted file mode 100644 index 0e0d3ec..0000000 --- a/LANCommander/Models/GameManifest.cs +++ /dev/null @@ -1,36 +0,0 @@ -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; } - } -} diff --git a/LANCommander/Services/ArchiveService.cs b/LANCommander/Services/ArchiveService.cs index 85d658c..f245bb6 100644 --- a/LANCommander/Services/ArchiveService.cs +++ b/LANCommander/Services/ArchiveService.cs @@ -3,6 +3,7 @@ using LANCommander.Data.Models; using LANCommander.Extensions; using LANCommander.Helpers; using LANCommander.Models; +using LANCommander.SDK; using System.IO.Compression; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; diff --git a/LANCommander/Services/GameService.cs b/LANCommander/Services/GameService.cs index b54f64f..0e44855 100644 --- a/LANCommander/Services/GameService.cs +++ b/LANCommander/Services/GameService.cs @@ -1,7 +1,10 @@ using LANCommander.Data; +using LANCommander.Data.Enums; using LANCommander.Data.Models; using LANCommander.Extensions; using LANCommander.Helpers; +using LANCommander.Models; +using LANCommander.SDK; using System.Drawing; namespace LANCommander.Services @@ -23,6 +26,86 @@ namespace LANCommander.Services await base.Delete(game); } + public async Task GetManifest(Guid id) + { + var game = await Get(id); + + if (game == null) + return null; + + var manifest = new GameManifest() + { + Title = game.Title, + SortTitle = game.SortTitle, + Description = game.Description, + ReleasedOn = game.ReleasedOn.GetValueOrDefault(), + Singleplayer = game.Singleplayer, + }; + + if (game.Genres != null && game.Genres.Count > 0) + manifest.Genre = game.Genres.Select(g => g.Name).ToArray(); + + if (game.Tags != null && game.Tags.Count > 0) + manifest.Tags = game.Tags.Select(g => g.Name).ToArray(); + + if (game.Publishers != null && game.Publishers.Count > 0) + manifest.Publishers = game.Publishers.Select(g => g.Name).ToArray(); + + if (game.Developers != null && game.Developers.Count > 0) + manifest.Developers = game.Developers.Select(g => g.Name).ToArray(); + + if (game.Archives != null && game.Archives.Count > 0) + manifest.Version = game.Archives.OrderByDescending(a => a.CreatedOn).First().Version; + + try + { + manifest.Icon = Convert.ToBase64String(GetIcon(game)); + } + catch { } + + if (game.Actions != null && game.Actions.Count > 0) + { + manifest.Actions = game.Actions.Select(a => new GameAction() + { + Name = a.Name, + Arguments = a.Arguments, + Path = a.Path, + WorkingDirectory = a.WorkingDirectory, + IsPrimaryAction = a.PrimaryAction + }).ToArray(); + } + + if (game.MultiplayerModes != null && game.MultiplayerModes.Count > 0) + { + var local = game.MultiplayerModes.FirstOrDefault(m => m.Type == MultiplayerType.Local); + var lan = game.MultiplayerModes.FirstOrDefault(m => m.Type == MultiplayerType.Lan); + var online = game.MultiplayerModes.FirstOrDefault(m => m.Type == MultiplayerType.Online); + + if (local != null) + manifest.LocalMultiplayer = new MultiplayerInfo() + { + MinPlayers = local.MinPlayers, + MaxPlayers = local.MaxPlayers, + }; + + if (lan != null) + manifest.LanMultiplayer = new MultiplayerInfo() + { + MinPlayers = lan.MinPlayers, + MaxPlayers = lan.MaxPlayers, + }; + + if (online != null) + manifest.LocalMultiplayer = new MultiplayerInfo() + { + MaxPlayers = online.MinPlayers, + MinPlayers = online.MaxPlayers, + }; + } + + return manifest; + } + public byte[] GetIcon(Game game) { var cachedPath = $"Icon/{game.Id}.png";