Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Ciriak committed May 14, 2020
2 parents 5833980 + 2b9bdae commit 9dacf68
Show file tree
Hide file tree
Showing 16 changed files with 361 additions and 147 deletions.
9 changes: 6 additions & 3 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
- Added support for cover images using [Steam Grid](https://github.com/boppreh/steamgrid) (Experimental)
- Added a settings panel for cover images
- Fixed shortcuts using a wrong label in the Steam library
- Fixed a bug where cover images couldn't be discovered until at least one game was launched
- Fixed a bug where some games where added to Steam with the wrong .exe
- Does not display a game in the menu if there is no executable to select
- Less notification, Steam scanner will be less intrusive
- Does not restart Steam by default
- When a game has been uninstalled, it shortcut is removed from your Steam library
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "steam-scanner",
"version": "0.2.8",
"version": "0.3.0",
"description": "Automatically add your game to you Steam library",
"main": "scanner.js",
"scripts": {
Expand Down Expand Up @@ -67,7 +67,7 @@
"bootstrap": "^4.4.1",
"colors": "^1.4.0",
"electron-is-dev": "^1.2.0",
"electron-log": "^4.1.1",
"electron-log": "^4.1.2",
"electron-updater": "^4.2.5",
"extract-file-icon": "^0.3.2",
"fs-extra": "^9.0.0",
Expand Down Expand Up @@ -112,4 +112,4 @@
},
"publish": true
}
}
}
22 changes: 18 additions & 4 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default class Config {
private scanner: SteamScanner;
version: string = "0.0.0";
configPath = path.join(app.getPath("appData"), appName);
configFilePath = path.join(this.configPath, "config.json")
configFilePath = path.join(this.configPath, "config.json");
reset: boolean = false;

get enableNotifications(): boolean {
return this._enableNotifications;
Expand Down Expand Up @@ -134,7 +135,7 @@ export default class Config {
*
* If unable to load the config, it will generate a clean one
*/
private load() {
private async load() {
try {
const config = readJsonSync(this.configFilePath) as IConfig;
this.enableNotifications = config.enableNotifications;
Expand All @@ -147,11 +148,24 @@ export default class Config {
this.enableGrid = config.enableGrid;
} catch (error) {
logWarn("Unable to load the config");
const config = this.writeDefaultConfig();
return config;
const newConfig = await this.resetConfig();
return newConfig;
}
}

/**
* Reset the whole config and clean the Steam shortcut files
*/
public async resetConfig(): Promise<IConfig> {
return new Promise(async (resolve) => {
logWarn("Cleaning the config...");
const config = this.writeDefaultConfig();
this.reset = true;
return resolve(config);
});

}


/**
* Write the current config to the config file
Expand Down
99 changes: 73 additions & 26 deletions src/GameHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import exeBlackList from "./library/ExeBlackList";
import { findIndex } from "lodash";
import gamesLibrary from "./library/games/GamesLibrary"
import IGame from "./interfaces/Game.interface";
import axios from "axios";
import { createWriteStream, ensureDirSync } from "fs-extra";
import { app } from "electron";
import defaultIcon from "./assets/scanner.png";
import { exists } from "fs-extra";
/**
* Provide utilities for game manipulations
*/
Expand All @@ -21,34 +20,40 @@ export default class GameHelper {
constructor(gameData: IGame, scanner: SteamScanner) {
this.scanner = scanner;
this.config = scanner.config;
this.gameData = this.checkGameData(gameData);
this.gameData = gameData;
this.checkGameData();
}



/**
* Check if some data already saved exist
* Check if some data already saved exist for the game
*/
private checkGameData(gameData: IGame): IGame {
try {
let gameConfig: IGame | null = null;
if (gameData.name && gameData.launcher && this.config.launchers[gameData.launcher]) {
const launcher = this.config.launchers[gameData.launcher];
if (launcher && launcher.games) {
gameConfig = launcher.games[gameData.name];
if (gameConfig) {
// if a config is found for this game, return it
return gameConfig
private async checkGameData(): Promise<IGame> {
return new Promise(async (resolve) => {
try {
let gameConfig: IGame | null = null;
if (this.gameData.name && this.gameData.launcher && this.config.launchers[this.gameData.launcher]) {
const launcher = this.config.launchers[this.gameData.launcher];
if (launcher && launcher.games) {
gameConfig = launcher.games[this.gameData.name];
if (gameConfig) {
// if a config is found for this game, return it
this.gameData = gameConfig;
return resolve(gameConfig);
}
}
}

// else return the original provided config
return resolve(this.gameData)
} catch (error) {
// in case of error return the original provided config
logWarn(error);
return resolve(this.gameData)
}
})

// else return the original provided config
return gameData
} catch (error) {
logWarn(error);
return gameData
}

}

Expand Down Expand Up @@ -173,18 +178,22 @@ export default class GameHelper {
if (launcher && launcher.games) {
launcher.games[this.gameData.name] = this.gameData;
}

}

/*
Here, we will listen for an active process to have the same name than a binarie found in the game files
add the game the the listener, things happend in "Scanner.ts"
*/
log(`Found ${colors.cyan(String(this.gameData.binaries.length))} possible executable(s) for the game ${colors.cyan(this.gameData.name)}`);
// notifier.notify({
// title: "Game found",
// message: `We have found ${this.gameData.binaries.length} files that can be the game executable, please select one`
// })

this.scanner.notificationsManager.notification({
icon: defaultIcon,
title: "Manual exe selection needed",
message: `We found various possible executables for ${this.gameData.label}, click on this notification to select the correct one`,
shouldOpenMenu: true
})



return resolve();
}
Expand All @@ -193,6 +202,44 @@ export default class GameHelper {

}

/**
* Check if a game is still installed on the computer
*
* If not, remove it's shortcut
* @param game
* @return refreshed game data or null if the game is not available anymore
*/
public checkGameInstallation(): Promise<boolean> {
const game = this.gameData;
return new Promise((resolve) => {
// check the game folder
exists(game.folderPath, async (folderExist) => {
if (!folderExist) {
logWarn(`Game folder for ${game.label} don't exists anymore... it's shortcut will be removed`);
return resolve(false);
}

// check the game exe
if (game.binarySet) {
exists(game.binaries[0], async (binaryExist) => {
if (!binaryExist) {
logWarn(`Executable for ${game.label} don't exists anymore... it's shortcut will be removed and the game data refreshed`);
await this.scanner.steam.removeShortcut(game);
// update the game instance
this.gameData.binarySet = false;
this.gameData.disableAutoAdd = true;
// return true (since the game is still installed)
return resolve(true);
}
});
}

return resolve(true);

});
});
}

/**
* Check if we know the game in the "library" if so, we set the stored properties
*/
Expand Down
39 changes: 30 additions & 9 deletions src/GridManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export enum GridManagerEvents {
RESET_STEAM_GRID = "GRID_RESET_STEAM_GRID",
}

const processTimeoutDelay = (60 * 1000) * 20; // 10min
const processTimeoutDelay = (60 * 1000) * 2; // 2min
const gridProcessStartDelay = 3000;


export default class GridManager {
Expand All @@ -27,7 +28,8 @@ export default class GridManager {
private shouldRerun: boolean = false;
private browserWindow?: BrowserWindow;
private steamGridProcess?: ChildProcessWithoutNullStreams;
private processTimeout?: NodeJS.Timeout;
private processQuitTimeout?: NodeJS.Timeout;
private processStartTimeout?: NodeJS.Timeout;
private gridOriginalExe = path.join(app.getAppPath(), "native", "steamgrid.exe");
private gridExe = path.join(app.getPath("appData"), "steam-scanner", "steamgrid.exe");
constructor(scanner: SteamScanner) {
Expand All @@ -46,7 +48,6 @@ export default class GridManager {
this.shouldRerun = false;
}


if (restart) {
this.shouldRerun = true;
}
Expand All @@ -59,6 +60,24 @@ export default class GridManager {
*/
getGrid() {

// clear the timeout
if (this.processStartTimeout) {
clearTimeout(this.processStartTimeout);
}

// set the timeout
this.processStartTimeout = setTimeout(() => {
this.startGridProcess();
}, gridProcessStartDelay)


}

/**
* Start a steamGrid process
*/
private startGridProcess() {

if (this.active) {
logWarn("A Steam Grid process is currently in progress, restarting...");
this.stopGrid(true);
Expand All @@ -67,7 +86,7 @@ export default class GridManager {

log(colors.magenta("Starting Steam Grid Process..."))

let args: string[] = ['--skipsteam', '--styles', 'alternate,white_logo'];
let args: string[] = ['--nonsteamonly'];

// set the steamGridDb token if available in the config
if (this.config.steamGridDbToken) {
Expand Down Expand Up @@ -99,12 +118,12 @@ export default class GridManager {
});

// clear the timeout
if (this.processTimeout) {
clearTimeout(this.processTimeout);
if (this.processQuitTimeout) {
clearTimeout(this.processQuitTimeout);
}

// set the timeout
this.processTimeout = setTimeout(() => {
this.processQuitTimeout = setTimeout(() => {
this.stopGrid();
}, processTimeoutDelay)

Expand Down Expand Up @@ -231,9 +250,11 @@ export default class GridManager {
/**
* Clear all items in the grid folder
*/
private async resetGrid() {
log(colors.magenta("Resetting the Steam grids..."));
public async resetGrid() {
log(colors.magenta("Cleaning the Steam grids..."));
// restart steam to prevent an issue with writing rights
this.scanner.steam.restartSteam();

for (const steamUser of this.scanner.steam.steamUsers) {
await steamUser.cleanGrid();
}
Expand Down
34 changes: 34 additions & 0 deletions src/Launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ILauncher, { IGameLocation, IInstallationState, IGamesCollection } from "
import { addDrivesToPossibleLocations, log, logWarn } from "./utils/helper.utils";
import GameHelper from "./GameHelper";
import SteamScanner from "./app";
import IGame from "./interfaces/Game.interface";

export abstract class Launcher implements ILauncher {
[propName: string]: any
Expand Down Expand Up @@ -208,6 +209,12 @@ export abstract class Launcher implements ILauncher {
const gameData = this.games[gameName];

const gameInstance = new GameHelper(this.games[gameName], this.scanner);
const isInstalled = await gameInstance.checkGameInstallation();
// skip if the game is not installed anymore
if (!isInstalled) {
await this.removeGame(gameInstance.gameData);
continue;
}

// force a label refresh every time
this.games[gameName].label = gameInstance.getLabel(this.games[gameName]);
Expand All @@ -229,6 +236,33 @@ export abstract class Launcher implements ILauncher {

}

/**
* Remove a game from the Steam library and the launcher instance
* @param game game to remove
*/
protected async removeGame(game: IGame): Promise<void> {
return new Promise(async (resolve) => {
await this.scanner.steam.removeShortcut(game);
this.scanner.notificationsManager.notification({
title: game.label + " removed",
message: game.label + "'s folder no longer existed<br>The game has been removed from your Steam library"
});

// delete the game from the launcher
delete this.games[game.name];
if (this.config.launchers[this.name]) {
// delete the game references in the config
delete this.config.launchers[this.name].games[game.name];
// force a save
this.config.launchers = { ...this.config.launchers };
}


return resolve();
});

}

protected isInGamesExcludeList(gameFolderName: string): boolean {
// no exclude // return false
if (!this.gamesPossibleLocations?.exclude) {
Expand Down
Loading

0 comments on commit 9dacf68

Please sign in to comment.