141 lines
4.3 KiB
Rust
141 lines
4.3 KiB
Rust
use dirs;
|
|
use ini::Ini;
|
|
use reqwest::Client;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json;
|
|
use std::{env, fs};
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct JsonGame {
|
|
game: JsonGameContent,
|
|
}
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct JsonGameContent {
|
|
game_name: String,
|
|
game_version: String,
|
|
available_game_stats: JsonAvailableGameStats,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct JsonAvailableGameStats {
|
|
achievements: Vec<JsonAchievement>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct JsonAchievement {
|
|
name: String,
|
|
defaultvalue: i32,
|
|
display_name: String,
|
|
hidden: i32,
|
|
description: String,
|
|
icon: String,
|
|
icongray: String,
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let client = Client::new();
|
|
let config_home = dirs::config_dir().unwrap().to_str().unwrap().to_string();
|
|
let api_key =
|
|
fs::read_to_string(format!("{config_home}/achievement-watcher/api-key.txt")).unwrap();
|
|
let api_key = api_key.trim();
|
|
let wine_home = env::var("WINEPREFIX").unwrap_or(env::var("HOME").unwrap() + ".wine");
|
|
let dirs = vec![
|
|
wine_home.clone() + "/drive_c/users/Public/Documents/Steam/CODEX",
|
|
wine_home.clone() + "/drive_c/users/Public/Documents/Steam/RUNE",
|
|
];
|
|
let ini_games = get_achievement_data_all(dirs);
|
|
println!("ini games: {:#?}", ini_games);
|
|
let game_data = get_steam_data(&client, api_key, "2310", "en").await;
|
|
println!("game_data: {:#?}", game_data);
|
|
}
|
|
|
|
async fn get_steam_data(client: &Client, key: &str, appid: &str, lang: &str) -> JsonGame {
|
|
let url = format!("https://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v0002/?key={key}&appid={appid}&l={lang}&format=json");
|
|
let json = client.get(url).send().await.unwrap().text().await.unwrap();
|
|
// fs::write("out.json", &json).unwrap();
|
|
// let json = fs::read_to_string("out.json").unwrap();
|
|
serde_json::from_str(&json).unwrap()
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct IniAchievement {
|
|
name: String,
|
|
achieved: bool,
|
|
current_progress: u32,
|
|
max_progress: u32,
|
|
unlock_time: u32,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct IniGame {
|
|
id: u32,
|
|
achievements: Vec<IniAchievement>,
|
|
}
|
|
|
|
impl IniGame {
|
|
fn new(id: u32) -> Self {
|
|
Self {
|
|
id,
|
|
achievements: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl IniAchievement {
|
|
fn new(name: String) -> Self {
|
|
Self {
|
|
name,
|
|
achieved: false,
|
|
current_progress: 0,
|
|
max_progress: 0,
|
|
unlock_time: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_achievement_data_all(dirs: Vec<String>) -> Vec<IniGame> {
|
|
let mut ini_games = Vec::new();
|
|
for dir in dirs {
|
|
let game_dirs = fs::read_dir(dir).unwrap();
|
|
for game_dir in game_dirs {
|
|
let game_dir = game_dir.unwrap();
|
|
let mut ini_game = IniGame::new(
|
|
game_dir
|
|
.file_name()
|
|
.to_str()
|
|
.unwrap()
|
|
.to_string()
|
|
.parse()
|
|
.unwrap(),
|
|
);
|
|
let game_dir_path = game_dir.path().to_str().unwrap().to_string();
|
|
let i = Ini::load_from_file(format!("{game_dir_path}/achievements.ini",)).unwrap();
|
|
for (sec, prop) in i.iter() {
|
|
if let Some(section) = sec {
|
|
if section == "SteamAchievements" {
|
|
continue;
|
|
}
|
|
let mut ini_achievement = IniAchievement::new(section.to_string());
|
|
for (k, v) in prop.iter() {
|
|
match k {
|
|
"Achieved" => ini_achievement.achieved = v.parse::<u32>().unwrap() == 1,
|
|
"CurProgress" => ini_achievement.current_progress = v.parse().unwrap(),
|
|
"MaxProgress" => ini_achievement.max_progress = v.parse().unwrap(),
|
|
"UnlockTime" => ini_achievement.unlock_time = v.parse().unwrap(),
|
|
s => panic!("unexpected achievement stat {s}"),
|
|
}
|
|
}
|
|
ini_game.achievements.push(ini_achievement);
|
|
}
|
|
}
|
|
ini_games.push(ini_game);
|
|
}
|
|
}
|
|
ini_games
|
|
}
|