Added ability for client to request the game manifest to provide metadata. Games can now be downloaded directly.
This commit is contained in:
parent
1a6dff63b2
commit
3c62e795e5
9 changed files with 197 additions and 57 deletions
|
@ -11,6 +11,8 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
using ICSharpCode.SharpZipLib.Core;
|
using ICSharpCode.SharpZipLib.Core;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
|
@ -39,6 +41,8 @@ namespace LANCommander.PlaynitePlugin
|
||||||
InstallDirectory = installDirectory
|
InstallDirectory = installDirectory
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Combine(installDirectory, "_manifest.yml"), GetManifest(gameId));
|
||||||
|
|
||||||
InvokeOnInstalled(new GameInstalledEventArgs(installInfo));
|
InvokeOnInstalled(new GameInstalledEventArgs(installInfo));
|
||||||
|
|
||||||
Plugin.UpdateGamesFromManifest();
|
Plugin.UpdateGamesFromManifest();
|
||||||
|
@ -48,16 +52,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
string tempFile = String.Empty;
|
string tempFile = String.Empty;
|
||||||
|
|
||||||
var archive = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault();
|
if (game != null)
|
||||||
|
|
||||||
if (archive != null)
|
|
||||||
{
|
{
|
||||||
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
||||||
{
|
{
|
||||||
progress.ProgressMaxValue = 100;
|
progress.ProgressMaxValue = 100;
|
||||||
progress.CurrentProgressValue = 0;
|
progress.CurrentProgressValue = 0;
|
||||||
|
|
||||||
var destination = Plugin.LANCommander.DownloadArchive(archive.Id, (changed) =>
|
var destination = Plugin.LANCommander.DownloadGame(game.Id, (changed) =>
|
||||||
{
|
{
|
||||||
progress.CurrentProgressValue = changed.ProgressPercentage;
|
progress.CurrentProgressValue = changed.ProgressPercentage;
|
||||||
}, (complete) =>
|
}, (complete) =>
|
||||||
|
@ -82,7 +84,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
return tempFile;
|
return tempFile;
|
||||||
}
|
}
|
||||||
else
|
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)
|
private string Extract(LANCommander.SDK.Models.Game game, string archivePath)
|
||||||
|
@ -142,5 +144,18 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
return destination;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using LANCommander.SDK.Models;
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Models;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using RestSharp.Extensions;
|
using RestSharp.Extensions;
|
||||||
using System;
|
using System;
|
||||||
|
@ -115,6 +116,16 @@ namespace LANCommander.PlaynitePlugin
|
||||||
return GetRequest<Game>($"/api/Games/{id}");
|
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)
|
public string DownloadArchive(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
||||||
{
|
{
|
||||||
return DownloadRequest($"api/Archives/Download/{id}", progressHandler, completeHandler);
|
return DownloadRequest($"api/Archives/Download/{id}", progressHandler, completeHandler);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using LANCommander.Models;
|
using LANCommander.PlaynitePlugin.Extensions;
|
||||||
|
using LANCommander.SDK;
|
||||||
using Playnite.SDK;
|
using Playnite.SDK;
|
||||||
using Playnite.SDK.Models;
|
using Playnite.SDK.Models;
|
||||||
using Playnite.SDK.Plugins;
|
using Playnite.SDK.Plugins;
|
||||||
|
@ -48,11 +49,11 @@ namespace LANCommander.PlaynitePlugin
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var games = LANCommander
|
var games = LANCommander
|
||||||
.GetGames()
|
.GetGames();
|
||||||
.Where(g => g.Archives != null && g.Archives.Count() > 0);
|
|
||||||
|
|
||||||
foreach (var game in games)
|
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 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}");
|
var iconUri = new Uri(new Uri(Settings.ServerAddress), $"Games/GetIcon/{game.Id}");
|
||||||
|
@ -60,15 +61,42 @@ namespace LANCommander.PlaynitePlugin
|
||||||
var metadata = new GameMetadata()
|
var metadata = new GameMetadata()
|
||||||
{
|
{
|
||||||
IsInstalled = existingGame != null,
|
IsInstalled = existingGame != null,
|
||||||
Name = game.Title,
|
Name = manifest.Title,
|
||||||
SortingName = game.SortTitle,
|
SortingName = manifest.SortTitle,
|
||||||
Description = game.Description,
|
Description = manifest.Description,
|
||||||
GameId = game.Id.ToString(),
|
GameId = game.Id.ToString(),
|
||||||
ReleaseDate = new ReleaseDate(game.ReleasedOn),
|
ReleaseDate = new ReleaseDate(manifest.ReleasedOn),
|
||||||
Version = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Version,
|
//Version = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Version,
|
||||||
Icon = new MetadataFile(iconUri.ToString())
|
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);
|
gameMetadata.Add(metadata);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LANCommander.Models
|
namespace LANCommander.SDK
|
||||||
{
|
{
|
||||||
public class GameManifest
|
public class GameManifest
|
||||||
{
|
{
|
||||||
|
@ -8,17 +9,19 @@ namespace LANCommander.Models
|
||||||
public string SortTitle { get; set; }
|
public string SortTitle { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public DateTime ReleasedOn { get; set; }
|
public DateTime ReleasedOn { get; set; }
|
||||||
public string[] Genre { get; set; }
|
public IEnumerable<string> Genre { get; set; }
|
||||||
public string[] Tags { get; set; }
|
public IEnumerable<string> Tags { get; set; }
|
||||||
public string[] Publishers { get; set; }
|
public IEnumerable<string> Publishers { get; set; }
|
||||||
public string[] Developers { get; set; }
|
public IEnumerable<string> Developers { get; set; }
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
public GameAction[] Actions { get; set; }
|
public IEnumerable<GameAction> Actions { get; set; }
|
||||||
public bool Singleplayer { get; set; }
|
public bool Singleplayer { get; set; }
|
||||||
public MultiplayerInfo LocalMultiplayer { get; set; }
|
public MultiplayerInfo LocalMultiplayer { get; set; }
|
||||||
public MultiplayerInfo LanMultiplayer { get; set; }
|
public MultiplayerInfo LanMultiplayer { get; set; }
|
||||||
public MultiplayerInfo OnlineMultiplayer { get; set; }
|
public MultiplayerInfo OnlineMultiplayer { get; set; }
|
||||||
|
|
||||||
|
public GameManifest() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameAction
|
public class GameAction
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using LANCommander.Data;
|
using LANCommander.Data;
|
||||||
using LANCommander.Data.Models;
|
using LANCommander.Data.Models;
|
||||||
|
using LANCommander.Extensions;
|
||||||
|
using LANCommander.Models;
|
||||||
|
using LANCommander.SDK;
|
||||||
using LANCommander.Services;
|
using LANCommander.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -30,5 +33,36 @@ namespace LANCommander.Controllers.Api
|
||||||
{
|
{
|
||||||
return await GameService.Get(id);
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using LANCommander.Data.Models;
|
using LANCommander.Data.Models;
|
||||||
using LANCommander.Extensions;
|
using LANCommander.Extensions;
|
||||||
using LANCommander.Models;
|
using LANCommander.Models;
|
||||||
|
using LANCommander.SDK;
|
||||||
using LANCommander.Services;
|
using LANCommander.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ using LANCommander.Data.Models;
|
||||||
using LANCommander.Extensions;
|
using LANCommander.Extensions;
|
||||||
using LANCommander.Helpers;
|
using LANCommander.Helpers;
|
||||||
using LANCommander.Models;
|
using LANCommander.Models;
|
||||||
|
using LANCommander.SDK;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
using LANCommander.Data;
|
using LANCommander.Data;
|
||||||
|
using LANCommander.Data.Enums;
|
||||||
using LANCommander.Data.Models;
|
using LANCommander.Data.Models;
|
||||||
using LANCommander.Extensions;
|
using LANCommander.Extensions;
|
||||||
using LANCommander.Helpers;
|
using LANCommander.Helpers;
|
||||||
|
using LANCommander.Models;
|
||||||
|
using LANCommander.SDK;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace LANCommander.Services
|
namespace LANCommander.Services
|
||||||
|
@ -23,6 +26,86 @@ namespace LANCommander.Services
|
||||||
await base.Delete(game);
|
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)
|
public byte[] GetIcon(Game game)
|
||||||
{
|
{
|
||||||
var cachedPath = $"Icon/{game.Id}.png";
|
var cachedPath = $"Icon/{game.Id}.png";
|
||||||
|
|
Loading…
Add table
Reference in a new issue