Added ability for client to request the game manifest to provide metadata. Games can now be downloaded directly.

dashboard
Pat Hartl 2023-01-14 15:09:45 -06:00
parent 1a6dff63b2
commit 3c62e795e5
9 changed files with 197 additions and 57 deletions

View File

@ -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;
}
}
}

View File

@ -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<Game>($"/api/Games/{id}");
}
public GameManifest GetGameManifest(Guid id)
{
return GetRequest<GameManifest>($"/api/Games/{id}/Manifest");
}
public string DownloadGame(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
{
return DownloadRequest($"/api/Games/{id}/Download", progressHandler, completeHandler);
}
public string DownloadArchive(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
{
return DownloadRequest($"api/Archives/Download/{id}", progressHandler, completeHandler);

View File

@ -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<MetadataProperty>()
};
if (manifest.Genre != null && manifest.Genre.Count() > 0)
metadata.Genres = new HashSet<MetadataProperty>(manifest.Genre.Select(g => new MetadataNameProperty(g)));
if (manifest.Developers != null && manifest.Developers.Count() > 0)
metadata.Developers = new HashSet<MetadataProperty>(manifest.Developers.Select(d => new MetadataNameProperty(d)));
if (manifest.Publishers != null && manifest.Publishers.Count() > 0)
metadata.Publishers = new HashSet<MetadataProperty>(manifest.Publishers.Select(p => new MetadataNameProperty(p)));
if (manifest.Tags != null && manifest.Tags.Count() > 0)
metadata.Tags = new HashSet<MetadataProperty>(manifest.Tags.Select(t => new MetadataNameProperty(t)));
metadata.Features = new HashSet<MetadataProperty>();
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);
};
}

View File

@ -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<string> Genre { get; set; }
public IEnumerable<string> Tags { get; set; }
public IEnumerable<string> Publishers { get; set; }
public IEnumerable<string> Developers { get; set; }
public string Version { get; set; }
public string Icon { get; set; }
public GameAction[] Actions { get; set; }
public IEnumerable<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 GameManifest() { }
}
public class GameAction

View File

@ -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<GameManifest> GetManifest(Guid id)
{
var manifest = await GameService.GetManifest(id);
return manifest;
}
[HttpGet("{id}/Download")]
public async Task<IActionResult> 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");
}
}
}

View File

@ -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;

View File

@ -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; }
}
}

View File

@ -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;

View File

@ -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<GameManifest> 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";