game-scanner 1.1.2

Game Scanner for any launcher and OS
use std::path::{Path, PathBuf};

use crate::{
    error::{Error, ErrorKind, Result},
    prelude::Game,
    steam::types::{SteamAppState, SteamUpdateResult},
    utils::string::remove_quotes,
};

pub fn read(file: &Path, launcher_executable: &Path, library_path: &Path) -> Result<Game> {
    let manifest_data = std::fs::read_to_string(&file).map_err(|error| {
        Error::new(
            ErrorKind::InvalidManifest,
            format!(
                "Error on read the Steam manifest: {} {}",
                file.display().to_string(),
                error.to_string()
            ),
        )
    })?;

    let manifest = manifest_data.split("\n").collect::<Vec<&str>>();

    let mut game = Game::default();
    game._type = String::from("steam");

    for file_line in manifest {
        let line = file_line
            .split("\t")
            .filter(|str| !str.trim().is_empty())
            .collect::<Vec<&str>>();

        if line.len() != 2 {
            continue;
        }

        let attr = remove_quotes(line.get(0).unwrap());
        let value = remove_quotes(line.get(1).unwrap());

        match attr.as_str() {
            "appid" => game.id = value,
            "name" => game.name = value,
            "StateFlags" => {
                let state = value.parse::<i64>().unwrap();

                game.state.installed = has_app_state(state, SteamAppState::FullyInstalled);

                game.state.needs_update = has_app_state(state, SteamAppState::UpdateRequired);

                game.state.downloading = has_app_state(state, SteamAppState::Downloading);
            }
            "UpdateResult" => {
                let state = value.parse::<i64>().unwrap();

                if game.state.needs_update && !game.state.downloading {
                    game.state.downloading =
                        has_update_result(state, SteamUpdateResult::Downloading);
                }
            }
            "BytesToDownload" => game.state.total_bytes = value.parse::<u64>().ok(),
            "BytesDownloaded" => game.state.received_bytes = value.parse::<u64>().ok(),
            "installdir" => {
                game.path = Some(PathBuf::from(library_path).join("common").join(value))
            }
            _ => {}
        }
    }

    if game.id == "228980" {
        return Err(Error::new(
            ErrorKind::IgnoredApp,
            format!("({}) {} is an invalid game", &game.id, &game.name),
        ));
    }

    game.commands.install = Some(vec![
        launcher_executable.display().to_string(),
        String::from("-silent"),
        format!("steam://install/{}", &game.id),
    ]);

    game.commands.launch = Some(vec![
        launcher_executable.display().to_string(),
        String::from("-silent"),
        format!("steam://run/{}", &game.id),
    ]);

    game.commands.uninstall = Some(vec![
        launcher_executable.display().to_string(),
        String::from("-silent"),
        format!("steam://uninstall/{}", &game.id),
    ]);

    return Ok(game);
}

fn has_app_state(state: i64, flag: SteamAppState) -> bool {
    if flag == SteamAppState::Invalid {
        return state == 0;
    }

    if flag == SteamAppState::Uninstalled {
        return state == 1;
    }

    (state & flag.get_code()) == flag.get_code()
}

fn has_update_result(state: i64, flag: SteamUpdateResult) -> bool {
    if flag == SteamUpdateResult::Downloading {
        return state == 0;
    }

    (state & flag.get_code()) == flag.get_code()
}