Initial Origin Support

This commit is contained in:
Philip
2021-10-01 22:26:29 +02:00
parent 272e198e85
commit d7deae57ad
8 changed files with 175 additions and 9 deletions
+6
View File
@@ -0,0 +1,6 @@
mod settings;
mod origin_platform;
mod origin_game;
pub use origin_platform::*;
pub use settings::*;
+18
View File
@@ -0,0 +1,18 @@
use steam_shortcuts_util::{shortcut::ShortcutOwned, Shortcut};
pub struct OriginGame {
pub id: String,
pub title: String,
}
impl From<OriginGame> for ShortcutOwned {
fn from(game: OriginGame) -> Self {
let launch = format!("origin2://game/launch?offerIds={}&autoDownload=1", game.id);
let shortcut = Shortcut::new(0, game.title.as_str(), launch.as_str(), "", "", "", "");
let mut owned_shortcut = shortcut.to_owned();
owned_shortcut.tags.push("Origin".to_owned());
owned_shortcut.tags.push("Ready TO Play".to_owned());
owned_shortcut.tags.push("Installed".to_owned());
owned_shortcut
}
}
+125
View File
@@ -0,0 +1,125 @@
use crate::platform::Platform;
use failure::*;
use nom::bytes::complete::take_until;
use std::{
fs::DirEntry,
path::{Path, PathBuf},
};
use super::{origin_game::OriginGame, OriginSettings};
pub struct OriginPlatform {
pub settings: OriginSettings,
}
impl Platform<OriginGame, OriginErrors> for OriginPlatform {
fn enabled(&self) -> bool {
self.settings.enabled
}
fn name(&self) -> &str {
"Origin"
}
fn get_shortcuts(&self) -> Result<Vec<OriginGame>, OriginErrors> {
let origin_folder = Path::new(
&self
.settings
.path
.clone()
.unwrap_or_else(|| get_default_location()),
)
.join("LocalContent");
if !origin_folder.exists() {
return Err(OriginErrors::PathNotFound {
path: origin_folder.to_str().unwrap().to_string(),
});
}
let game_folders =
origin_folder
.read_dir()
.map_err(|e| OriginErrors::CouldNotReadGameDir {
path: origin_folder,
error: format!("{:?}", e),
})?;
let games = game_folders
.filter_map(|folder| folder.ok())
.filter_map(|game_folder| {
let game_title = game_folder.file_name().to_string_lossy().to_string();
let mfst_content = get_folder_mfst_file_content(&game_folder.path());
let id = match mfst_content {
Some(c) => parse_id_from_file(c.as_str())
.ok()
.map(|(_, id_str)| String::from(id_str)),
None => None,
};
id.map(|id| OriginGame {
id: id.to_string(),
title: game_title,
})
});
Ok(games.collect())
}
}
fn get_folder_mfst_file_content(game_folder_path: &Path) -> Option<String> {
let game_folder_files = game_folder_path.read_dir();
if let Ok(game_folder_files) = game_folder_files {
let mfst_file = game_folder_files
.filter_map(|file| file.ok())
.filter(is_mfst_file)
.next()
.map(|file| std::fs::read_to_string(&file.path()));
return match mfst_file {
Some(mfst_file) => mfst_file.ok(),
None => None,
};
}
None
}
fn is_mfst_file(file: &DirEntry) -> bool {
file.path()
.extension()
.map(|ex| ex.to_str().unwrap_or("") == "mfst")
.unwrap_or(false)
}
fn parse_id_from_file(i: &str) -> nom::IResult<&str, &str> {
let (i, _) = take_until("&id=")(i)?;
let (i, _) = nom::bytes::complete::tag("&id=")(i)?;
take_until("&")(i)
}
#[cfg(target_os = "linux")]
fn get_default_location() -> String {
//If we don't have a home drive we have to just die
let home = std::env::var("HOME").expect("Expected a home variable to be defined");
format!("{}/.origin/", home)
}
#[cfg(target_os = "windows")]
fn get_default_location() -> String {
let key = "PROGRAMDATA";
let program_data = std::env::var(key).expect("Expected a APPDATA variable to be defined");
Path::new(&program_data)
.join("Origin")
.to_str()
.unwrap()
.to_string()
}
#[derive(Debug, Fail)]
pub enum OriginErrors {
#[fail(
display = "Origin path: {} could not be found. Try to specify a different path for Origin.",
path
)]
PathNotFound { path: String },
#[fail(
display = "Could not read Origin directory: {:?}. Error: {}",
path, error
)]
CouldNotReadGameDir { path: PathBuf, error: String },
}
+8
View File
@@ -0,0 +1,8 @@
use serde::Deserialize;
#[derive(Debug, Deserialize,Clone)]
pub struct OriginSettings {
pub enabled: bool,
pub path: Option<String>,
}