mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 05:53:41 +02:00
Initial GOG integration
This commit is contained in:
@@ -3,6 +3,9 @@ debug= false
|
|||||||
[origin]
|
[origin]
|
||||||
enabled = false
|
enabled = false
|
||||||
|
|
||||||
|
[gog]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
[epic_games]
|
[epic_games]
|
||||||
enabled = false
|
enabled = false
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub(crate) struct GogConfig {
|
||||||
|
#[serde(alias = "installationPaths")]
|
||||||
|
pub installation_paths: Vec<String>,
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use steam_shortcuts_util::{shortcut::ShortcutOwned, Shortcut};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub(crate) struct GogGame {
|
||||||
|
pub name: String,
|
||||||
|
#[serde(alias = "gameId")]
|
||||||
|
pub game_id: String,
|
||||||
|
#[serde(alias = "playTasks")]
|
||||||
|
pub play_tasks: Option<Vec<PlayTask>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub(crate) struct PlayTask {
|
||||||
|
pub category: Option<String>,
|
||||||
|
#[serde(alias = "isPrimary")]
|
||||||
|
pub is_primary: Option<bool>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub path: Option<String>,
|
||||||
|
#[serde(alias = "type")]
|
||||||
|
pub task_type: String,
|
||||||
|
#[serde(alias = "workingDir")]
|
||||||
|
pub working_dir: Option<String>,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct GogShortcut {
|
||||||
|
pub name: String,
|
||||||
|
pub game_folder: String,
|
||||||
|
pub path: String,
|
||||||
|
pub working_dir:String,
|
||||||
|
pub game_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GogShortcut> for ShortcutOwned {
|
||||||
|
fn from(gogs: GogShortcut) -> Self {
|
||||||
|
let exe = Path::new(&gogs.game_folder).join(gogs.path);
|
||||||
|
let icon_file = format!("goggame-{}.ico", gogs.game_id);
|
||||||
|
let icon_path = Path::new(&gogs.game_folder).join(&icon_file);
|
||||||
|
let icon = if icon_path.exists() {
|
||||||
|
icon_path.to_str().unwrap().to_string()
|
||||||
|
} else {
|
||||||
|
exe.to_str().unwrap_or("").to_string()
|
||||||
|
};
|
||||||
|
let shortcut = Shortcut::new(
|
||||||
|
0,
|
||||||
|
gogs.name.as_str(),
|
||||||
|
exe.to_str().unwrap(),
|
||||||
|
gogs.working_dir.as_str(),
|
||||||
|
icon.as_str(),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
let mut owned_shortcut = shortcut.to_owned();
|
||||||
|
owned_shortcut.tags.push("Gog".to_owned());
|
||||||
|
owned_shortcut.tags.push("Ready TO Play".to_owned());
|
||||||
|
owned_shortcut.tags.push("Installed".to_owned());
|
||||||
|
|
||||||
|
owned_shortcut
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
use failure::*;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::{gog::gog_config::GogConfig, platform::Platform};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
gog_game::{GogGame, GogShortcut},
|
||||||
|
GogSettings,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct GogPlatform {
|
||||||
|
pub settings: GogSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform<GogShortcut, GogErrors> for GogPlatform {
|
||||||
|
fn enabled(&self) -> bool {
|
||||||
|
self.settings.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"Gog"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_shortcuts(&self) -> Result<Vec<GogShortcut>, GogErrors> {
|
||||||
|
let gog_location = self
|
||||||
|
.settings
|
||||||
|
.location
|
||||||
|
.as_ref()
|
||||||
|
.map(|location| Path::new(&location).to_path_buf())
|
||||||
|
.unwrap_or_else(default_location);
|
||||||
|
if !gog_location.exists() {
|
||||||
|
return Err(GogErrors::PathNotFound { path: gog_location });
|
||||||
|
}
|
||||||
|
let config_path = gog_location.join("config.json");
|
||||||
|
if !config_path.exists() {
|
||||||
|
return Err(GogErrors::ConfigFileNotFound { path: config_path });
|
||||||
|
}
|
||||||
|
let install_locations = get_install_locations(config_path)?;
|
||||||
|
dbg!(&install_locations);
|
||||||
|
let mut game_folders = vec![];
|
||||||
|
for install_location in install_locations {
|
||||||
|
let path = Path::new(&install_location);
|
||||||
|
if path.exists() {
|
||||||
|
let dirs = path.read_dir();
|
||||||
|
if let Ok(dirs) = dirs {
|
||||||
|
for dir in dirs {
|
||||||
|
if let Ok(dir) = dir {
|
||||||
|
if let Ok(file_type) = dir.file_type() {
|
||||||
|
if file_type.is_dir() {
|
||||||
|
game_folders.push(dir.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut games = vec![];
|
||||||
|
for game_folder in &game_folders {
|
||||||
|
if let Ok(files) = game_folder.read_dir() {
|
||||||
|
for file in files {
|
||||||
|
if let Ok(file) = file {
|
||||||
|
if let Some(file_name) = file.file_name().to_str() {
|
||||||
|
if file_name.starts_with("goggame-") {
|
||||||
|
if let Some(extension) = file.path().extension() {
|
||||||
|
if let Some(extension) = extension.to_str() {
|
||||||
|
if extension == "info" {
|
||||||
|
// Finally we know we can parse this as a game
|
||||||
|
if let Ok(content) =
|
||||||
|
std::fs::read_to_string(file.path())
|
||||||
|
{
|
||||||
|
if let Ok(gog_game) =
|
||||||
|
serde_json::from_str::<GogGame>(&content)
|
||||||
|
{
|
||||||
|
games.push((gog_game, game_folder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut shortcuts = vec![];
|
||||||
|
for (game, game_folder) in games {
|
||||||
|
if let Some(folder_path) = game_folder.to_str() {
|
||||||
|
if let Some(tasks) = &game.play_tasks {
|
||||||
|
if let Some(primary_task) = tasks.iter().find(|t| {
|
||||||
|
t.is_primary.unwrap_or_default()
|
||||||
|
&& t.task_type == "FileTask"
|
||||||
|
&& t.category.as_ref().unwrap_or(&String::from("")) == "game"
|
||||||
|
}) {
|
||||||
|
if let Some(task_path) = &primary_task.path {
|
||||||
|
let full_path = game_folder.join(&task_path);
|
||||||
|
if let Some(full_path) = full_path.to_str() {
|
||||||
|
let folder_path = folder_path.to_string();
|
||||||
|
|
||||||
|
let working_dir = match &primary_task.working_dir {
|
||||||
|
Some(working_dir) => game_folder
|
||||||
|
.join(working_dir)
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or(folder_path.as_str())
|
||||||
|
.to_string(),
|
||||||
|
None => folder_path.to_string(),
|
||||||
|
};
|
||||||
|
let shortcut = GogShortcut {
|
||||||
|
name: game.name,
|
||||||
|
game_folder: folder_path,
|
||||||
|
working_dir,
|
||||||
|
game_id: game.game_id,
|
||||||
|
path: full_path.to_string(),
|
||||||
|
};
|
||||||
|
shortcuts.push(shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(shortcuts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_install_locations(path: PathBuf) -> Result<Vec<String>, GogErrors> {
|
||||||
|
let data_res =
|
||||||
|
std::fs::read_to_string(&path).map_err(|e| GogErrors::ConfigFileCouldNotBeRead {
|
||||||
|
path: path.clone(),
|
||||||
|
error: format!("{}", e),
|
||||||
|
})?;
|
||||||
|
let config: GogConfig =
|
||||||
|
serde_json::from_str(&data_res).map_err(|e| GogErrors::ConfigFileCouldNotBeRead {
|
||||||
|
path,
|
||||||
|
error: format!("{}", e),
|
||||||
|
})?;
|
||||||
|
Ok(config.installation_paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_location() -> PathBuf {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
let key = "PROGRAMDATA";
|
||||||
|
let program_data = std::env::var(key).expect("Expected a APPDATA variable to be defined");
|
||||||
|
Path::new(&program_data).join("GOG.com").join("Galaxy")
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
let home = std::env::var("HOME").expect("Expected a home variable to be defined");
|
||||||
|
Path::new(&home).join("GOG.com").join("Galaxy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
pub enum GogErrors {
|
||||||
|
#[fail(
|
||||||
|
display = "Gog path: {:?} could not be found. Try to specify a different path for Gog.",
|
||||||
|
path
|
||||||
|
)]
|
||||||
|
PathNotFound { path: PathBuf },
|
||||||
|
|
||||||
|
#[fail(display = "Gog config file not found at path: {:?}", path)]
|
||||||
|
ConfigFileNotFound { path: PathBuf },
|
||||||
|
|
||||||
|
#[fail(
|
||||||
|
display = "Gog config file at path: {:?} could not be red {}",
|
||||||
|
path, error
|
||||||
|
)]
|
||||||
|
ConfigFileCouldNotBeRead { path: PathBuf, error: String },
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct GogSettings {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub location: Option<String>,
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
mod gog_config;
|
||||||
|
mod gog_game;
|
||||||
|
mod gog_platform;
|
||||||
|
mod gog_settings;
|
||||||
|
|
||||||
|
pub use gog_platform::*;
|
||||||
|
pub use gog_settings::*;
|
||||||
+10
@@ -1,11 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
itch::ItchPlatform,
|
itch::ItchPlatform,
|
||||||
origin::OriginPlatform,
|
origin::OriginPlatform,
|
||||||
|
gog::GogPlatform,
|
||||||
steamgriddb::{download_images, CachedSearch},
|
steamgriddb::{download_images, CachedSearch},
|
||||||
};
|
};
|
||||||
#[cfg(feature = "ui")]
|
#[cfg(feature = "ui")]
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use std::{fs::File, io::Write, path::Path};
|
use std::{fs::File, io::Write, path::Path};
|
||||||
|
mod gog;
|
||||||
mod egs;
|
mod egs;
|
||||||
mod itch;
|
mod itch;
|
||||||
mod legendary;
|
mod legendary;
|
||||||
@@ -221,6 +223,14 @@ async fn run_sync(settings: &Settings) -> Result<(), Box<dyn Error>> {
|
|||||||
&mut new_user_shortcuts,
|
&mut new_user_shortcuts,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
update_platform_shortcuts(
|
||||||
|
&GogPlatform{
|
||||||
|
settings: settings.gog.clone(),
|
||||||
|
},
|
||||||
|
&mut new_user_shortcuts,
|
||||||
|
);
|
||||||
|
|
||||||
let shortcuts = new_user_shortcuts.iter().map(|f| f.borrow()).collect();
|
let shortcuts = new_user_shortcuts.iter().map(|f| f.borrow()).collect();
|
||||||
|
|
||||||
save_shortcuts(&shortcuts, Path::new(&shortcut_info.path));
|
save_shortcuts(&shortcuts, Path::new(&shortcut_info.path));
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
egs::EpicGamesLauncherSettings, itch::ItchSettings, legendary::LegendarySettings,
|
egs::EpicGamesLauncherSettings, gog::GogSettings, itch::ItchSettings,
|
||||||
origin::OriginSettings, steam::SteamSettings, steamgriddb::SteamGridDbSettings,
|
legendary::LegendarySettings, origin::OriginSettings, steam::SteamSettings,
|
||||||
|
steamgriddb::SteamGridDbSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
use config::{Config, ConfigError, Environment, File};
|
use config::{Config, ConfigError, Environment, File};
|
||||||
@@ -16,6 +17,7 @@ pub struct Settings {
|
|||||||
pub steamgrid_db: SteamGridDbSettings,
|
pub steamgrid_db: SteamGridDbSettings,
|
||||||
pub steam: SteamSettings,
|
pub steam: SteamSettings,
|
||||||
pub origin: OriginSettings,
|
pub origin: OriginSettings,
|
||||||
|
pub gog: GogSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
|
|||||||
Reference in New Issue
Block a user