diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5d2fadc..3270f57 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,11 @@ jobs: cd ItchIoIntegration dotnet publish -o ../Release/plugins/ItchIoIntegration -p:Configuration=Release + - name: Build RemoteDownloaderPlugin + run: | + cd RemoteDownloaderPlugin + dotnet publish -o ../Release/plugins/RemoteDownloaderPlugin -p:Configuration=Release + - name: Build SteamGridDb Middleware run: | cd SteamGridDbMiddleware @@ -114,6 +119,11 @@ jobs: cd ItchIoIntegration dotnet publish -o ../Release/plugins/ItchIoIntegration -p:Configuration=Release + - name: Build RemoteDownloaderPlugin + run: | + cd RemoteDownloaderPlugin + dotnet publish -o ../Release/plugins/RemoteDownloaderPlugin -p:Configuration=Release + - name: Build SteamGridDb Middleware run: | cd SteamGridDbMiddleware diff --git a/Plugins.txt b/Plugins.txt index 813a129..5ce7398 100644 --- a/Plugins.txt +++ b/Plugins.txt @@ -5,4 +5,5 @@ ItchIoIntegration LegendaryIntegration LocalGames SteamExporterPlugin -SteamGridDbMiddleware \ No newline at end of file +SteamGridDbMiddleware +RemoteDownloaderPlugin \ No newline at end of file diff --git a/RemoteDownloaderPlugin/Game/GameDownload.cs b/RemoteDownloaderPlugin/Game/GameDownload.cs index 495b750..28e8392 100644 --- a/RemoteDownloaderPlugin/Game/GameDownload.cs +++ b/RemoteDownloaderPlugin/Game/GameDownload.cs @@ -8,20 +8,20 @@ namespace RemoteDownloaderPlugin.Game; public class GameDownload : ProgressStatus { - private IEntry _entry; + private OnlineGameDownload _entry; private int _lastSecond = 0; private readonly CancellationTokenSource _cts = new(); private bool _doneDownloading = false; public long TotalSize { get; private set; } public string Version { get; private set; } public GameType Type { get; private set; } - public string BaseFileName { get; private set; } + public string Filename { get; private set; } public string BasePath { get; private set; } public ContentTypes InstalledEntries { get; private set; } private DateTimeOffset _downloadStart = DateTimeOffset.Now; - public GameDownload(IEntry entry) + public GameDownload(OnlineGameDownload entry) { _entry = entry; InstalledEntries = new(); @@ -49,50 +49,47 @@ public async Task Download(IApp app) { _doneDownloading = false; - if (_entry is EmuEntry emuEntry) - await DownloadEmu(app, emuEntry); - else if (_entry is PcEntry pcEntry) - await DownloadPc(app, pcEntry); + if (_entry.Platform == "Pc") + await DownloadPc(app); else - throw new Exception("Download failed: Unknown type"); + await DownloadEmu(app); } - private async Task DownloadEmu(IApp app, EmuEntry entry) + private async Task DownloadEmu(IApp app) { Type = GameType.Emu; - if (entry.Files.Count(x => x.Type == "base") != 1) + if (_entry.Files.Count(x => x.Type == DownloadType.Base) != 1) { throw new Exception("Multiple base images, impossible download"); } - Line2 = $"{entry.Files.Count(x => x.Type == "base")} base, {entry.Files.Count(x => x.Type == "update")} update, {entry.Files.Count(x => x.Type == "dlc")} dlc"; - BasePath = Path.Join(app.GameDir, "Remote", entry.Emu); + Line2 = $"{_entry.Files.Count(x => x.Type == DownloadType.Base)} base, {_entry.Files.Count(x => x.Type == DownloadType.Update)} update, {_entry.Files.Count(x => x.Type == DownloadType.Dlc)} dlc"; + BasePath = Path.Join(app.GameDir, "Remote", _entry.Platform); string baseGamePath = null; - var extraFilesPath = Path.Join(app.GameDir, "Remote", entry.Emu, entry.GameId); + var extraFilesPath = Path.Join(BasePath, _entry.Id); Directory.CreateDirectory(BasePath); Directory.CreateDirectory(extraFilesPath); using HttpClient client = new(); - for (int i = 0; i < entry.Files.Count; i++) + for (int i = 0; i < _entry.Files.Count; i++) { - Progress localProcess = new(); localProcess.ProgressChanged += (sender, f) => { - var part = (float)1 / entry.Files.Count; - var add = (float)i / entry.Files.Count; + var part = (float)1 / _entry.Files.Count; + var add = (float)i / _entry.Files.Count; OnProgressUpdate(null, part * f + add); }; - var fileEntry = entry.Files[i]; - var destPath = Path.Join(fileEntry.Type == "base" ? BasePath : extraFilesPath, fileEntry.Name); + var fileEntry = _entry.Files[i]; + var destPath = Path.Join(fileEntry.Type == DownloadType.Base ? BasePath : extraFilesPath, fileEntry.Name); InstalledEntries.Add(fileEntry.Type); - if (fileEntry.Type == "base") + if (fileEntry.Type == DownloadType.Base) { baseGamePath = destPath; - BaseFileName = fileEntry.Name; + Filename = fileEntry.Name; } var fs = new FileStream(destPath, FileMode.Create); @@ -121,13 +118,13 @@ private async Task DownloadEmu(IApp app, EmuEntry entry) } TotalSize = (await Task.Run(() => LauncherGamePlugin.Utils.DirSize(new(extraFilesPath)))) + (new FileInfo(baseGamePath!)).Length; - Version = entry.Files.Last(x => x.Type is "base" or "update").Version; + Version = _entry.Files.Last(x => x.Type is DownloadType.Base or DownloadType.Update).Version; } - private async Task DownloadPc(IApp app, PcEntry entry) + private async Task DownloadPc(IApp app) { Type = GameType.Pc; - BasePath = Path.Join(app.GameDir, "Remote", "Pc", entry.GameId); + BasePath = Path.Join(app.GameDir, "Remote", "Pc", _entry.Id); Directory.CreateDirectory(BasePath); using HttpClient client = new(); @@ -137,7 +134,7 @@ private async Task DownloadPc(IApp app, PcEntry entry) try { // TODO: Fix security vuln, zips can have backwards paths - using HttpResponseMessage response = await client.GetAsync(entry.Url, HttpCompletionOption.ResponseHeadersRead, _cts.Token); + using HttpResponseMessage response = await client.GetAsync(_entry.Files.First().Url, HttpCompletionOption.ResponseHeadersRead, _cts.Token); response.EnsureSuccessStatusCode(); await using var responseStream = await response.Content.ReadAsStreamAsync(); var interceptor = @@ -178,9 +175,10 @@ private async Task DownloadPc(IApp app, PcEntry entry) Directory.Delete(BasePath, true); throw; } - + + InstalledEntries.Base++; TotalSize = await Task.Run(() => LauncherGamePlugin.Utils.DirSize(new(BasePath))); - Version = entry.Version; + Version = _entry.Files.First().Version; } public void Stop() diff --git a/RemoteDownloaderPlugin/Game/InstalledGame.cs b/RemoteDownloaderPlugin/Game/InstalledGame.cs index 08d4159..26a0fe2 100644 --- a/RemoteDownloaderPlugin/Game/InstalledGame.cs +++ b/RemoteDownloaderPlugin/Game/InstalledGame.cs @@ -8,7 +8,7 @@ namespace RemoteDownloaderPlugin.Game; public class InstalledGame : IGame { - public string InternalName => Game.Id; + public string InternalName { get; } public string Name => Game.Name; public bool IsRunning { get; set; } = false; public IGameSource Source => _plugin; @@ -18,12 +18,7 @@ public bool HasImage(ImageType type) public bool IsEmu => _type == GameType.Emu; - public ContentTypes InstalledContentTypes => IsEmu - ? _emuGame.Types - : new ContentTypes() - { - Base = 1 - }; + public ContentTypes InstalledContentTypes => Game.InstalledContent; public Task GetImage(ImageType type) { @@ -38,41 +33,33 @@ public bool HasImage(ImageType type) public InstalledStatus InstalledStatus => InstalledStatus.Installed; public Platform EstimatedGamePlatform => IsEmu - ? LauncherGamePlugin.Utils.GuessPlatformBasedOnString(_plugin.Storage.Data.EmuProfiles.FirstOrDefault(x => x.Platform == _emuGame!.Emu)?.ExecPath) + ? LauncherGamePlugin.Utils.GuessPlatformBasedOnString(_plugin.Storage.Data.EmuProfiles.FirstOrDefault(x => x.Platform == Game.Platform)?.ExecPath) : LauncherGamePlugin.Utils.GuessPlatformBasedOnString(_pcLaunchDetails!.LaunchExec); - - public string GamePlatform => IsEmu - ? _emuGame!.Emu - : "Pc"; - + public ProgressStatus? ProgressStatus => null; public event Action? OnUpdate; public void InvokeOnUpdate() => OnUpdate?.Invoke(); - public IInstalledGame Game { get; } + public InstalledGameContent Game { get; } private Plugin _plugin; private PcLaunchDetails? _pcLaunchDetails; - private InstalledEmuGame? _emuGame; private GameType _type; - public InstalledGame(IInstalledGame game, Plugin plugin) + public InstalledGame(InstalledGameContent game, Plugin plugin) { Game = game; _plugin = plugin; - _type = game is InstalledEmuGame ? GameType.Emu : GameType.Pc; + _type = game.Platform == "Pc" ? GameType.Pc : GameType.Emu; _pcLaunchDetails = null; + InternalName = $"{Game.Id}_{LauncherGamePlugin.Utils.OnlyLetters(Game.Platform).ToLower()}"; if (_type == GameType.Pc) { var fullPath = Path.Join(game.BasePath, "game.json"); _pcLaunchDetails = PcLaunchDetails.GetFromPath(fullPath); } - else - { - _emuGame = (game as InstalledEmuGame)!; - } } public void Play() @@ -81,14 +68,14 @@ public void Play() { if (IsEmu) { - var emuProfile = _plugin.Storage.Data.EmuProfiles.FirstOrDefault(x => x.Platform == _emuGame!.Emu); + var emuProfile = _plugin.Storage.Data.EmuProfiles.FirstOrDefault(x => x.Platform == Game.Platform); if (emuProfile == null) { - throw new Exception($"No '{_emuGame!.Emu}' emulation profile exists"); + throw new Exception($"No '{Game.Platform}' emulation profile exists"); } - var baseGamePath = Path.Join(Game.BasePath, _emuGame!.BaseFilename); + var baseGamePath = Path.Join(Game.BasePath, Game.Filename); LaunchParams args = new(emuProfile.ExecPath, emuProfile.CliArgs.Replace("{EXEC}", $"\"{baseGamePath}\""), emuProfile.WorkingDirectory, this, @@ -112,12 +99,12 @@ public void Play() public void Delete() { + bool success = false; if (IsEmu) { - var baseGamePath = Path.Join(Game.BasePath, _emuGame.BaseFilename); + var baseGamePath = Path.Join(Game.BasePath, Game.Filename); var extraDir = Path.Join(Game.BasePath, Game.Id); - var success = false; - + try { File.Delete(baseGamePath); @@ -125,33 +112,23 @@ public void Delete() success = true; } catch {} - - var game = _plugin.Storage.Data.EmuGames.Find(x => x.Id == Game.Id); - _plugin.Storage.Data.EmuGames.Remove(game!); - - if (!success) - { - _plugin.App.ShowTextPrompt("Failed to delete files. Game has been unlinked"); - } } else { - var success = false; - try { Directory.Delete(Game.BasePath, true); success = true; } catch {} + } + + var game = _plugin.Storage.Data.Games.Find(x => x.Id == Game.Id && x.Platform == Game.Platform); + _plugin.Storage.Data.Games.Remove(game!); - var game = _plugin.Storage.Data.PcGames.Find(x => x.Id == Game.Id); - _plugin.Storage.Data.PcGames.Remove(game!); - - if (!success) - { - _plugin.App.ShowTextPrompt("Failed to delete files. Game has been unlinked"); - } + if (!success) + { + _plugin.App.ShowTextPrompt("Failed to delete files. Game has been unlinked"); } _plugin.App.ReloadGames(); diff --git a/RemoteDownloaderPlugin/Game/OnlineGame.cs b/RemoteDownloaderPlugin/Game/OnlineGame.cs index 2e259ac..52cb785 100644 --- a/RemoteDownloaderPlugin/Game/OnlineGame.cs +++ b/RemoteDownloaderPlugin/Game/OnlineGame.cs @@ -8,12 +8,11 @@ namespace RemoteDownloaderPlugin.Game; public class OnlineGame : IGame { - public string InternalName => Entry.GameId; - public string Name => $"{Entry.GameName} ({Platform})"; + public string InternalName { get; } + public string Name => $"{Game.Name} ({Game.Platform})"; public bool IsRunning { get; set; } = false; public IGameSource Source => _plugin; - public long? Size => Entry.GameSize; - public string Platform { get; private set; } + public long? Size => Game.GameSize; public bool HasImage(ImageType type) => ImageTypeToUri(type) != null; @@ -25,7 +24,7 @@ public bool HasImage(ImageType type) if (url == null) return Task.FromResult(null); - return Storage.Cache($"{Entry.GameId}_{type}.jpg", () => Storage.ImageDownload(url)); + return Storage.Cache($"{Game.Id}_{type}.jpg", () => Storage.ImageDownload(url)); } public InstalledStatus InstalledStatus => InstalledStatus.NotInstalled; @@ -34,45 +33,40 @@ public bool HasImage(ImageType type) public event Action? OnUpdate; public void InvokeOnUpdate() => OnUpdate?.Invoke(); - public IEntry Entry { get; } + public OnlineGameDownload Game { get; } private Plugin _plugin; private GameDownload? _download = null; - public OnlineGame(IEntry entry, Plugin plugin) + public OnlineGame(OnlineGameDownload game, Plugin plugin) { - Entry = entry; + Game = game; _plugin = plugin; - Platform = (entry is EmuEntry emuEntry) - ? emuEntry.Emu - : "Pc"; + InternalName = $"{Game.Id}_{LauncherGamePlugin.Utils.OnlyLetters(Game.Platform).ToLower()}"; } public async Task Download() { - if (Entry is EmuEntry emuEntry) + var baseFiles = Game.Files.Where(x => x.Type == DownloadType.Base).ToList(); + if (baseFiles.Count >= 2) { - var baseFiles = emuEntry.Files.Where(x => x.Type == "base").ToList(); - if (baseFiles.Count >= 2) + var form = new Form(new()); + + form.FormEntries.Add(Form.TextBox("Pick a base edition of the game:", FormAlignment.Center, "Bold")); + + baseFiles.ForEach(x => form.FormEntries.Add(Form.ClickableLinkBox($"{x.Name}: {x.DownloadSize.ReadableSize()}", _ => { - var form = new Form(new()); - - form.FormEntries.Add(Form.TextBox("Pick a base edition of the game:", FormAlignment.Center, "Bold")); - - baseFiles.ForEach(x => form.FormEntries.Add(Form.ClickableLinkBox($"{x.Name}: {x.DownloadSize.ReadableSize()}", _ => - { - emuEntry.Files.RemoveAll(y => y.Type == "base" && y.Name != x.Name); - Download(); - _plugin.App.HideForm(); - }, FormAlignment.Left))); - - form.FormEntries.Add(Form.Button("Back", _ => _plugin.App.HideForm())); - - _plugin.App.ShowForm(form); - return; - } + Game.Files.Where(y => y.Type == DownloadType.Base && y.Name != x.Name).ToList().ForEach(y => Game.Files.Remove(y)); + Download(); + _plugin.App.HideForm(); + }, FormAlignment.Left))); + + form.FormEntries.Add(Form.Button("Back", _ => _plugin.App.HideForm())); + + _plugin.App.ShowForm(form); + return; } - _download = new GameDownload(Entry); + _download = new GameDownload(Game); OnUpdate?.Invoke(); try @@ -85,35 +79,19 @@ public async Task Download() OnUpdate?.Invoke(); return; } - - if (_download.Type == GameType.Emu) - { - var entry = Entry as EmuEntry; - _plugin.Storage.Data.EmuGames.Add(new() - { - Id = Entry.GameId, - Name = Entry.GameName, - Emu = entry!.Emu, - GameSize = _download.TotalSize, - Version = _download.Version, - BaseFilename = _download.BaseFileName, - Images = Entry.Img, - Types = _download.InstalledEntries, - BasePath = _download.BasePath - }); - } - else + + _plugin.Storage.Data.Games.Add(new() { - _plugin.Storage.Data.PcGames.Add(new() - { - Id = Entry.GameId, - Name = Entry.GameName, - GameSize = _download.TotalSize, - Version = _download.Version, - Images = Entry.Img, - BasePath = _download.BasePath - }); - } + Id = Game.Id, + Name = Game.Name, + Platform = Game.Platform, + GameSize = _download.TotalSize, + Version = _download.Version, + Filename = _download.Filename, + Images = Game.Images, + InstalledContent = _download.InstalledEntries, + BasePath = _download.BasePath + }); _plugin.Storage.Save(); _plugin.App.ReloadGames(); @@ -130,11 +108,11 @@ public void Stop() private Uri? ImageTypeToUri(ImageType type) => type switch { - ImageType.Background => Entry.Img.Background, - ImageType.VerticalCover => Entry.Img.VerticalCover, - ImageType.HorizontalCover => Entry.Img.HorizontalCover, - ImageType.Logo => Entry.Img.Logo, - ImageType.Icon => Entry.Img.Icon, + ImageType.Background => Game.Images.Background, + ImageType.VerticalCover => Game.Images.VerticalCover, + ImageType.HorizontalCover => Game.Images.HorizontalCover, + ImageType.Logo => Game.Images.Logo, + ImageType.Icon => Game.Images.Icon, _ => null }; } \ No newline at end of file diff --git a/RemoteDownloaderPlugin/Plugin.cs b/RemoteDownloaderPlugin/Plugin.cs index f4b282e..b5a0975 100644 --- a/RemoteDownloaderPlugin/Plugin.cs +++ b/RemoteDownloaderPlugin/Plugin.cs @@ -28,6 +28,7 @@ public class Plugin : IGameSource { App = app; Storage = new(app, "remote_games.json"); + Storage.Data.Migrate(); await FetchRemote(); return null; @@ -60,7 +61,7 @@ public List GetGameCommands(IGame game) new Command(game.IsRunning ? "Running" : "Launch", installedGame.Play), new Command("Open in File Manager", installedGame.OpenInFileManager), new Command($"Version: {installedGame.Game.Version}"), - new Command($"Platform: {installedGame.GamePlatform}"), + new Command($"Platform: {installedGame.Game.Platform}"), }; if (installedGame.IsEmu) @@ -83,12 +84,10 @@ public List GetGameCommands(IGame game) public async Task> GetGames() { - List installedGames = Storage.Data.EmuGames.Select(x => new InstalledGame(x, this)) - .Concat(Storage.Data.PcGames.Select(x => new InstalledGame(x, this))).ToList(); - - List installedIds = installedGames.Select(x => x.Game.Id).ToList(); - - return _onlineGames.Where(x => !(installedIds.Contains(x.Entry.GameId) || Storage.Data.HiddenRemotePlatforms.Contains(x.Platform))) + var installedGames = Storage.Data.Games.Select(x => new InstalledGame(x, this)).ToList(); + var installedIds = new HashSet(installedGames.Select(x => x.InternalName)); + + return _onlineGames.Where(x => !(installedIds.Contains(x.InternalName) || Storage.Data.HiddenRemotePlatforms.Contains(x.Game.Platform))) .Select(x => (IGame)x) .Concat(installedGames.Select(x => (IGame)x)) .ToList(); @@ -105,11 +104,9 @@ public async Task FetchRemote() client.Timeout = TimeSpan.FromSeconds(10); var data = await client.GetStringAsync(Storage.Data.IndexUrl); _cachedRemote = JsonConvert.DeserializeObject(data)!; - - _onlineGames = _cachedRemote.Emu.Select(x => new OnlineGame(x, this)) - .Concat(_cachedRemote.Pc.Select(x => new OnlineGame(x, this))).ToList(); - _platforms = _onlineGames.Select(x => x.Platform).Distinct().ToList(); + _onlineGames = _cachedRemote.Games.Select(x => new OnlineGame(x, this)).ToList(); + _platforms = _onlineGames.Select(x => x.Game.Platform).Distinct().ToList(); return true; } diff --git a/RemoteDownloaderPlugin/Remote.cs b/RemoteDownloaderPlugin/Remote.cs index b833778..134b2ef 100644 --- a/RemoteDownloaderPlugin/Remote.cs +++ b/RemoteDownloaderPlugin/Remote.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace RemoteDownloaderPlugin; @@ -11,56 +12,40 @@ public class Images public Uri VerticalCover { get; set; } } -public class EmuFileEntry +public enum DownloadType +{ + Base, + Update, + Dlc, + Extra +} + +public class OnlineGameDownloadFileEntry { [JsonProperty("download_size")] public long DownloadSize { get; set; } + [JsonProperty("installed_size")] + public long InstalledSize { get; set; } public string Ext { get; set; } public string Name { get; set; } - public string Type { get; set; } + [JsonConverter(typeof(StringEnumConverter))] + public DownloadType Type { get; set; } public Uri Url { get; set; } public string Version { get; set; } } -public interface IEntry -{ - public string GameId { get; } - public string GameName { get; } - public Images Img { get; } - public long GameSize { get; } -} - -public class EmuEntry : IEntry +public class OnlineGameDownload { - [JsonProperty("game_id")] - public string GameId { get; set; } - [JsonProperty("game_name")] - public string GameName { get; set; } - public List Files { get; set; } - public Images Img { get; set; } - public string Emu { get; set; } - - [System.Text.Json.Serialization.JsonIgnore] - public long GameSize => Files.Sum(x => x.DownloadSize); -} - -public class PcEntry : IEntry -{ - [JsonProperty("game_id")] - public string GameId { get; set; } - [JsonProperty("game_name")] - public string GameName { get; set; } - [JsonProperty("download_size")] - public long DownloadSize { get; set; } - [JsonProperty("game_size")] - public long GameSize { get; set; } - public Uri Url { get; set; } - public string Version { get; set; } - public Images Img { get; set; } + public IList Files { get; set; } + public string Id { get; set; } + public string Name { get; set; } + public Images Images { get; set; } + public string Platform { get; set; } + [JsonIgnore] + public long GameSize => Files.Sum(x => x.InstalledSize); } public class Remote { - public List Pc { get; set; } = new(); - public List Emu { get; set; } = new(); + public IList Games { get; set; } = []; } \ No newline at end of file diff --git a/RemoteDownloaderPlugin/Store.cs b/RemoteDownloaderPlugin/Store.cs index e695a69..a31414e 100644 --- a/RemoteDownloaderPlugin/Store.cs +++ b/RemoteDownloaderPlugin/Store.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace RemoteDownloaderPlugin; @@ -8,6 +9,7 @@ public enum GameType Emu, } +[Obsolete] public interface IInstalledGame { public string Id { get; } @@ -25,6 +27,7 @@ public class ContentTypes public int Dlc { get; set; } public int Extra { get; set; } + [Obsolete] public void Add(string type) { switch (type) @@ -44,6 +47,25 @@ public void Add(string type) } } + public void Add(DownloadType type) + { + switch (type) + { + case DownloadType.Base: + Base++; + break; + case DownloadType.Update: + Update++; + break; + case DownloadType.Dlc: + Dlc++; + break; + case DownloadType.Extra: + Extra++; + break; + } + } + public override string ToString() => "Content: " + string.Join(", ", new List() { @@ -54,6 +76,7 @@ public override string ToString() }.Where(x => !string.IsNullOrEmpty(x))); } +[Obsolete] public class InstalledEmuGame : IInstalledGame { public string Id { get; set; } @@ -67,6 +90,7 @@ public class InstalledEmuGame : IInstalledGame public string BasePath { get; set; } } +[Obsolete] public class InstalledPcGame : IInstalledGame { public string Id { get; set; } @@ -85,11 +109,65 @@ public class EmuProfile public string CliArgs { get; set; } = ""; } +public class InstalledGameContent +{ + public string Id { get; set; } + public string Name { get; set; } + public string Platform { get; set; } + public long GameSize { get; set; } + public string Version { get; set; } + public string Filename { get; set; } + public Images Images { get; set; } + public ContentTypes InstalledContent { get; set; } = new(); + public string BasePath { get; set; } +} + public class Store { + public List Games { get; set; } = new(); + [Obsolete] public List EmuGames { get; set; } = new(); + [Obsolete] public List PcGames { get; set; } = new(); public List EmuProfiles { get; set; } = new(); public List HiddenRemotePlatforms { get; set; } = new(); public string IndexUrl { get; set; } = ""; + + public void Migrate() + { + EmuGames.ForEach(x => + { + Games.Add(new() + { + Id = x.Id, + Name = x.Name, + Platform = x.Emu, + GameSize = x.GameSize, + Version = x.Version, + Filename = x.BaseFilename, + Images = x.Images, + InstalledContent = x.Types, + BasePath = x.BasePath, + }); + }); + + PcGames.ForEach(x => + { + Games.Add(new() + { + Id = x.Id, + Name = x.Name, + Platform = "Pc", + GameSize = x.GameSize, + Version = x.Version, + Filename = null, + Images = x.Images, + InstalledContent = new(){ Base = 1 }, + BasePath = x.BasePath, + }); + }); + + PcGames.Clear(); + EmuGames.Clear(); + } } \ No newline at end of file