Skip to content

Commit 967465d

Browse files
authored
Backup shortcuts (#144)
* Add initial option to back up shortcuts * Show list of backups * Reload backups on change * Restore backups * Improve UX of backup ui * Reorganize ui * Update version in cargo.toml * Update flatpak description * Update cargo-lock.json
1 parent f5fef33 commit 967465d

File tree

9 files changed

+265
-33
lines changed

9 files changed

+265
-33
lines changed

Cargo.lock

Lines changed: 25 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,61 @@
11
[package]
2-
name = "boilr"
3-
version = "1.3.6"
42
edition = "2021"
3+
name = "boilr"
4+
version = "1.3.7"
55

6-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
76
[dependencies]
8-
steam_shortcuts_util = "1.1.7"
9-
steamgriddb_api = "^0.3.0"
10-
serde = { version = "^1.0.137", features = ["derive"] }
11-
serde_json = "^1.0.81"
12-
tokio = { version = "^1.18.2", features = ["full"] }
13-
reqwest = { version = "^0.11.10", default_features = false }
7+
base64 = "^0.13.0"
8+
chrono = "^0.4.19"
149
config = "^0.11.0"
10+
copypasta = "0.7.1"
1511
failure = "^0.1.8"
16-
nom = "^7.1.1"
1712
flate2 = "^1.0.23"
18-
futures = { version = "^0.3.21" }
19-
dashmap = { version = "^5.3.3", features = ["serde"] }
2013
is_executable = "^1.0.1"
14+
nom = "^7.1.1"
2115
rusty-leveldb = "^0.3.6"
22-
base64 = "^0.13.0"
23-
eframe = { version = "^0.18.0" }
24-
egui = { version = "^0.18.1" }
25-
image = { version = "0.24.2", features = ["png"] }
26-
toml = { version = "^0.5.9" }
16+
serde_json = "^1.0.81"
17+
sqlite = "^0.26.0"
18+
steam_shortcuts_util = "^1.1.7"
19+
steamgriddb_api = "^0.3.0"
2720
sysinfo = "^0.23.12"
28-
sqlite = "0.26.0"
29-
copypasta = "0.7.1"
3021

31-
[target.'cfg(windows)'.dependencies]
32-
winreg = "0.10.1"
22+
[dependencies.dashmap]
23+
features = ["serde"]
24+
version = "^5.3.3"
25+
26+
[dependencies.eframe]
27+
version = "^0.18.0"
28+
29+
[dependencies.egui]
30+
version = "^0.18.1"
31+
32+
[dependencies.futures]
33+
version = "^0.3.21"
34+
35+
[dependencies.image]
36+
features = ["png"]
37+
version = "^0.24.2"
38+
39+
[dependencies.reqwest]
40+
default_features = false
41+
version = "^0.11.10"
42+
43+
[dependencies.serde]
44+
features = ["derive"]
45+
version = "^1.0.137"
46+
47+
[dependencies.tokio]
48+
features = ["full"]
49+
version = "^1.18.2"
50+
51+
[dependencies.toml]
52+
version = "^0.5.9"
53+
54+
[target]
55+
[target."cfg(windows)"]
56+
[target."cfg(windows)".build-dependencies]
57+
winres = "^0.1"
58+
59+
[target."cfg(windows)".dependencies]
60+
winreg = "^0.10.1"
3361

34-
[target.'cfg(windows)'.build-dependencies]
35-
winres = "0.1"

flatpak/cargo-lock.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,19 @@
402402
"dest": "cargo/vendor/cgl-0.3.2",
403403
"dest-filename": ".cargo-checksum.json"
404404
},
405+
{
406+
"type": "archive",
407+
"archive-type": "tar-gzip",
408+
"url": "https://static.crates.io/crates/chrono/chrono-0.4.19.crate",
409+
"sha256": "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73",
410+
"dest": "cargo/vendor/chrono-0.4.19"
411+
},
412+
{
413+
"type": "inline",
414+
"contents": "{\"package\": \"670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73\", \"files\": {}}",
415+
"dest": "cargo/vendor/chrono-0.4.19",
416+
"dest-filename": ".cargo-checksum.json"
417+
},
405418
{
406419
"type": "archive",
407420
"archive-type": "tar-gzip",
@@ -3327,6 +3340,19 @@
33273340
"dest": "cargo/vendor/tiff-0.7.2",
33283341
"dest-filename": ".cargo-checksum.json"
33293342
},
3343+
{
3344+
"type": "archive",
3345+
"archive-type": "tar-gzip",
3346+
"url": "https://static.crates.io/crates/time/time-0.1.43.crate",
3347+
"sha256": "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438",
3348+
"dest": "cargo/vendor/time-0.1.43"
3349+
},
3350+
{
3351+
"type": "inline",
3352+
"contents": "{\"package\": \"ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438\", \"files\": {}}",
3353+
"dest": "cargo/vendor/time-0.1.43",
3354+
"dest-filename": ".cargo-checksum.json"
3355+
},
33303356
{
33313357
"type": "archive",
33323358
"archive-type": "tar-gzip",

flatpak/io.github.philipk.boilr.appdata.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<p>This little tool will show games from other games platforms in your Steam library.
1111
It uses the Steam 3rd party shortcuts feature and does not require you to set up anything.
1212
The goal is that you do not have to leave your Steam library to launch games from other launchers/stores, so that you can find all the games that you have available.
13-
Optionally you can set BoilR up to automatically download artwork from SteamGridDB.</p>
13+
You can also use BoilR to manually and automatically download custom art from SteamGridDB.</p>
1414
</description>
1515
<screenshots>
1616
<screenshot type="default">
@@ -25,7 +25,12 @@ https://hughsie.github.io/oars/index.html
2525
-->
2626
<content_rating type="oars-1.1" />
2727
<releases>
28-
<release version="1.3.5" date="2022-05-17">
28+
<release version="1.3.7" date="2022-05-17">
29+
<description>
30+
<p>Back up your shortcuts and restore them later</p>
31+
</description>
32+
</release>
33+
<release version="1.3.6" date="2022-05-17">
2934
<description>
3035
<p>Automatically find Steam installed through flatpak</p>
3136
</description>

src/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ pub fn get_cache_file() -> PathBuf {
3737
get_config_folder().join("cache.json").to_path_buf()
3838
}
3939

40+
pub fn get_backups_flder() -> PathBuf {
41+
let backups_path = get_config_folder().join("backup");
42+
let _ = create_dir_all(&backups_path);
43+
backups_path.to_path_buf()
44+
}
45+
4046
#[cfg(target_family = "unix")]
4147
pub fn get_boilr_links_path() -> PathBuf {
4248
get_config_folder().join("links").to_path_buf()

src/ui/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod defines;
2+
mod ui_backup;
23
mod ui_image_download;
34
mod ui_import_games;
45
mod ui_settings;
56
mod uiapp;
67

78
pub use defines::*;
9+
pub use ui_backup::*;
810
pub use ui_image_download::*;
911
pub use ui_import_games::*;
1012
pub use ui_settings::*;

src/ui/ui_backup.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use std::path::{Path, PathBuf};
2+
3+
use chrono::Local;
4+
use egui::ScrollArea;
5+
6+
use crate::{
7+
config::get_backups_flder,
8+
steam::{get_shortcuts_paths, SteamSettings},
9+
};
10+
11+
use super::MyEguiApp;
12+
13+
#[derive(Default)]
14+
pub struct BackupState {
15+
pub available_backups: Option<Vec<PathBuf>>,
16+
pub last_restore: Option<PathBuf>,
17+
}
18+
19+
impl MyEguiApp {
20+
pub fn render_backup(&mut self, ui: &mut egui::Ui) {
21+
ui.heading("Backups");
22+
ui.label("Here you can restore backed up shortcuts files");
23+
ui.label("Click a backup to restore it, your current shortcuts will be backed up first");
24+
ui.add_space(15.0);
25+
26+
if let Some(last_restore) = self.backup_state.last_restore.as_ref() {
27+
ui.heading(format!("Last restored {:?}", last_restore));
28+
}
29+
30+
if ui.button("Click here to create a new backup").clicked() {
31+
backup_shortcuts(&self.settings.steam);
32+
self.backup_state.available_backups = None;
33+
}
34+
35+
let available_backups = self
36+
.backup_state
37+
.available_backups
38+
.get_or_insert_with(|| load_backups());
39+
40+
if available_backups.is_empty() {
41+
ui.label("No backups found, they will be created every time you run import");
42+
} else {
43+
ScrollArea::vertical()
44+
.stick_to_right()
45+
.auto_shrink([false, true])
46+
.show(ui, |ui| {
47+
for backup_path in available_backups {
48+
if ui
49+
.button(backup_path.to_string_lossy().to_string())
50+
.clicked()
51+
{
52+
//Restore
53+
backup_shortcuts(&self.settings.steam);
54+
if restore_backup(&self.settings.steam, backup_path.as_path()) {
55+
self.backup_state.last_restore = Some(backup_path.clone());
56+
}
57+
}
58+
}
59+
});
60+
}
61+
62+
63+
}
64+
}
65+
66+
pub fn restore_backup(steam_settings: &SteamSettings, shortcut_path: &Path) -> bool {
67+
let file_name = shortcut_path.file_name().unwrap();
68+
let paths = get_shortcuts_paths(steam_settings);
69+
if let Ok(paths) = paths {
70+
for user in paths {
71+
if let Some(user_shortcut_path) = user.shortcut_path {
72+
if file_name.to_string_lossy().starts_with(&user.user_id) {
73+
std::fs::copy(shortcut_path, Path::new(&user_shortcut_path)).unwrap();
74+
println!("Restored shortcut to path : {}", user_shortcut_path);
75+
return true;
76+
}
77+
}
78+
}
79+
}
80+
return false;
81+
}
82+
83+
pub fn load_backups() -> Vec<PathBuf> {
84+
let backup_folder = get_backups_flder();
85+
let files = std::fs::read_dir(&backup_folder);
86+
let mut result = vec![];
87+
if let Ok(files) = files {
88+
for file in files {
89+
if let Ok(file) = file {
90+
if file
91+
.path()
92+
.extension()
93+
.unwrap_or_default()
94+
.to_string_lossy()
95+
== "vdf"
96+
{
97+
result.push(file.path().to_path_buf());
98+
}
99+
}
100+
}
101+
}
102+
result.sort();
103+
result.reverse();
104+
return result;
105+
}
106+
107+
pub fn backup_shortcuts(steam_settings: &SteamSettings) {
108+
let backup_folder = get_backups_flder();
109+
let paths = get_shortcuts_paths(&steam_settings);
110+
let date = Local::now();
111+
let date_string = date.format("%Y-%m-%d-%H-%M-%S");
112+
if let Ok(user_infos) = paths {
113+
for user_info in user_infos {
114+
if let Some(shortcut_path) = user_info.shortcut_path {
115+
let new_path = backup_folder.join(format!(
116+
"{}-{}-shortcuts.vdf",
117+
user_info.user_id, date_string
118+
));
119+
println!("Backed up shortcut at: {:?}", new_path);
120+
std::fs::copy(&shortcut_path, &new_path).unwrap();
121+
}
122+
}
123+
}
124+
}

src/ui/ui_import_games.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::sync;
99

1010
use crate::sync::{download_images, SyncProgress};
1111

12-
use super::ImageSelectState;
12+
use super::{ImageSelectState, backup_shortcuts};
1313
use super::{
1414
ui_colors::{BACKGROUND_COLOR, EXTRA_BACKGROUND_COLOR},
1515
MyEguiApp,
@@ -42,6 +42,9 @@ impl<T> FetcStatus<T> {
4242
}
4343

4444
impl MyEguiApp {
45+
46+
47+
4548
pub(crate) fn render_import_games(&mut self, ui: &mut egui::Ui) {
4649
ui.heading("Import Games");
4750

@@ -118,6 +121,7 @@ impl MyEguiApp {
118121
self.rt.spawn_blocking(move || {
119122
MyEguiApp::save_settings_to_file(&settings);
120123
let mut some_sender = Some(sender);
124+
backup_shortcuts(&settings.steam);
121125
let usersinfo = sync::run_sync(&settings, &mut some_sender).unwrap();
122126
let task = download_images(&settings, &usersinfo, &mut some_sender);
123127
block_on(task);

0 commit comments

Comments
 (0)