From 67f704563b2db70166617eace4795e9df676c1c4 Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Fri, 7 Jun 2024 17:36:10 -0400 Subject: [PATCH] #71: Add game menu option to open backup directory --- CHANGELOG.md | 6 ++-- lang/en-US.ftl | 2 ++ src/Etc.cs | 22 ++++++++++++++ src/LudusaviPlaynite.cs | 37 +++++++++++++++++++++++- src/LudusaviPlayniteSettingsView.xaml.cs | 12 +------- src/Models.cs | 2 ++ src/Translator.cs | 5 ++++ 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfce8da..8f1b6b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,14 @@ * In a game's context menu, backup comments are now displayed, if any have been added in Ludusavi. If a backup is from another OS than Windows, that is also indicated. + * In a game's context menu, you can now open that game's backup directory. + This requires Ludusavi v0.24.0 or newer. * Fixed: * In some cases where Playnite and Ludusavi used different names for a game, the game's context menu would not list its backups. - This now works properly in more cases if you use Ludusavi 0.24.0 or newer. + This now works properly in more cases if you use Ludusavi v0.24.0 or newer. * Changed: - * The recommended version of Ludusavi is now 0.24.0. You can download the latest release here: + * The recommended version of Ludusavi is now v0.24.0. You can download the latest release here: https://github.com/mtkennerly/ludusavi/releases * In a game's context menu, backups are now sorted newest to oldest. diff --git a/lang/en-US.ftl b/lang/en-US.ftl index b077155..68f8a3a 100644 --- a/lang/en-US.ftl +++ b/lang/en-US.ftl @@ -124,3 +124,5 @@ unrecognized-game = Ludusavi does not recognize {$game} look-up-as-other-title = Look up with another title look-up-as-normal-title = Look up with default title + +open-backup-directory = Open backup directory diff --git a/src/Etc.cs b/src/Etc.cs index 7f40492..4dae24a 100644 --- a/src/Etc.cs +++ b/src/Etc.cs @@ -2,11 +2,15 @@ using System.Collections.Generic; using System.Linq; using System; +using System.Diagnostics; +using System.Text.RegularExpressions; namespace LudusaviPlaynite { public static class Etc { + private static Regex homeDir = new Regex("^~"); + public static bool IsOnSteam(Game game) { return game.Source?.Name == "Steam" @@ -22,5 +26,23 @@ public static bool IsOnPc(Game game) || game.Platforms.Any(x => pcSpecs.Contains(x.SpecificationId)) || game.Platforms.Any(x => pcNames.Contains(x.Name)); } + + public static string NormalizePath(string path) + { + return homeDir.Replace(path, Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)).Replace("/", "\\"); + } + + public static bool OpenDir(string path) + { + try + { + Process.Start(NormalizePath(path)); + return true; + } + catch + { + return false; + } + } } } diff --git a/src/LudusaviPlaynite.cs b/src/LudusaviPlaynite.cs index 338f5b0..f5826e3 100644 --- a/src/LudusaviPlaynite.cs +++ b/src/LudusaviPlaynite.cs @@ -70,6 +70,7 @@ public class LudusaviPlaynite : GenericPlugin private LudusaviVersion appVersion { get; set; } = new LudusaviVersion(new Version(0, 0, 0)); private Dictionary titles { get; set; } = new Dictionary(); private Dictionary> backups { get; set; } = new Dictionary>(); + private Dictionary backupPaths { get; set; } = new Dictionary(); private List manifestGames { get; set; } = new List(); private List manifestGamesWithSaveDataByTitle { get; set; } = new List(); private List manifestGamesWithSaveDataBySteamId { get; set; } = new List(); @@ -226,6 +227,28 @@ public override IEnumerable GetGameMenuItems(GetGameMenuItemsArgs ); } + if (menuArgs.Games.Count == 1) + { + var backupPath = GetBackupPath(menuArgs.Games[0]); + if (backupPath != null) + { + items.Add( + new GameMenuItem + { + Description = translator.OpenBackupDirectory(), + MenuSection = translator.Ludusavi(), + Action = args => + { + if (!Etc.OpenDir(backupPath)) + { + ShowError(this.translator.CannotOpenFolder()); + } + } + } + ); + } + } + if (menuArgs.Games.Count == 1) { var title = menuArgs.Games[0].Name; @@ -500,7 +523,14 @@ public void RefreshLudusaviBackups() var (code, response) = InvokeLudusavi(new Invocation(Mode.Backups).PathIf(settings.BackupPath, settings.OverrideBackupPath)); if (response?.Games != null) { - this.backups = response?.Games.ToDictionary(pair => pair.Key, pair => pair.Value.Backups); + foreach (var pair in response?.Games) + { + this.backups.Add(pair.Key, pair.Value.Backups); + if (!string.IsNullOrEmpty(pair.Value.BackupPath)) + { + this.backupPaths.Add(pair.Key, pair.Value.BackupPath); + } + } } if (this.settings.TagGamesWithBackups) @@ -1527,6 +1557,11 @@ private List GetBackups(Game game) return ret; } + private string GetBackupPath(Game game) + { + return GetDictValue(this.backupPaths, GetTitle(game) ?? GetGameNameWithAlt(game), null); + } + private V GetDictValue(Dictionary dict, K key, V fallback) { if (dict == null || key == null) diff --git a/src/LudusaviPlayniteSettingsView.xaml.cs b/src/LudusaviPlayniteSettingsView.xaml.cs index 8e94fec..c692771 100644 --- a/src/LudusaviPlayniteSettingsView.xaml.cs +++ b/src/LudusaviPlayniteSettingsView.xaml.cs @@ -25,7 +25,6 @@ public partial class LudusaviPlayniteSettingsView : UserControl { private LudusaviPlaynite plugin; private Translator translator; - private Regex homeDir = new Regex("^~"); public LudusaviPlayniteSettingsView(LudusaviPlaynite plugin, Translator translator) { @@ -34,11 +33,6 @@ public LudusaviPlayniteSettingsView(LudusaviPlaynite plugin, Translator translat this.translator = translator; } - private string NormalizePath(string path) - { - return homeDir.Replace(path, Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)).Replace("/", "\\"); - } - public void OnBrowseExecutablePath(object sender, RoutedEventArgs e) { var choice = this.plugin.PlayniteApi.Dialogs.SelectFile(translator.SelectFileExecutableFilter()); @@ -59,11 +53,7 @@ public void OnBrowseBackupPath(object sender, RoutedEventArgs e) public void OnOpenBackupPath(object sender, RoutedEventArgs e) { - try - { - Process.Start(NormalizePath(plugin.settings.BackupPath)); - } - catch + if (!Etc.OpenDir(plugin.settings.BackupPath)) { this.plugin.ShowError(this.translator.CannotOpenFolder()); } diff --git a/src/Models.cs b/src/Models.cs index 5fe3ee9..6818fcd 100644 --- a/src/Models.cs +++ b/src/Models.cs @@ -484,6 +484,8 @@ public struct ApiGame public Dictionary Registry; [JsonProperty("backups")] public List Backups; + [JsonProperty("backupPath")] + public string BackupPath; } public struct ApiResponse diff --git a/src/Translator.cs b/src/Translator.cs index c44987b..3bcb1a9 100644 --- a/src/Translator.cs +++ b/src/Translator.cs @@ -661,5 +661,10 @@ public string LookUpAsNormalTitle() { return Translate("look-up-as-normal-title"); } + + public string OpenBackupDirectory() + { + return Translate("open-backup-directory"); + } } }