Skip to content

Commit

Permalink
auto kill steam is working beautifully on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
cbartondock committed Jun 8, 2024
1 parent 5ff69dd commit 31a2a40
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 53 deletions.
29 changes: 24 additions & 5 deletions src/lang/en-US/markdown/settings.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
## General Settings
### Check for updates on start `[Recommend enabled]`
Check if an update for SRM is available and prompt to update each time SRM launches.
### Auto kill Steam
SRM will attempt to kill all running instances of Steam whenever it needs to read/write collections information (specifically when saving to steam from `Add Games`, when removing all games from `Settings`, and when refreshing games from `View Games`).
### Auto restart Steam
SRM will attempt to restart Steam after killing it and completing whatever collections related task required killing Steam in the first place. Requires `Auto kill Steam` to be enabled.
### Offline mode `[Recommend disabled]`

When enabled SRM makes no network requests, useful if you only want to use SRM for local images.
### Automatically clear log before testing parsers `[Recommend enabled]`
When enabled the log is cleared each time a parser is tested.
When enabled the log is cleared each time a parser is tested.
## Add Games
### Show current steam images by default `[Recommend enabled]`
When enabled this setting tells SRM to default to whatever artwork is currently in steam for a given app. If it is disabled, then every time SRM is run (and saved) all artwork will be reset.
### Remove shortcuts for disabled parsers `[Recommend disabled]`
When enabled disabling a parser and running SRM will remove all added entries and artwork for the disabled parser. Useful if you want your steam library to be in 1-1 correspondence with enabled parsers.

### Disable saving of steam categories `[Recommend disabled]`
SRM will not write any collections information when saving to Steam. This allows SRM to perform its tasks while Steam is still running, at the obvious cost that added games will not be categorized.
### Hide Steam username from preview
Steam does not allow user's to alter their Steam usernames. In some cases (childish names, dead names, etc), users may no longer wish to see their Steam usernames. This setting hides it from `Add Games`.
### Remove all added games and controllers
Undo all SRM added changes from Steam.
### Remove all controllers only
Undo all SRM added controller settings from Steam.
## Fuzzy Matcher Settings
### Log matching results `[Recommend disabled]`
When enabled more verbose logs appear for the fuzzy title matcher in the `Event log`. Useful for debugging incorrect fuzzy matches.

### Reset fuzzy list
Resets the stored list of titles used for fuzzy matching to the list of titles returned by `SteamGridDB` (removes any user added titles).
### Reset fuzzy cache
Expand All @@ -25,9 +37,16 @@ When enabled, SRM will pull all available artwork for every game, rather than pu
Global setting to enable/disable particular image providers. Current options are `SteamGridDB` and `Steam Official`.
### DNS manual override
Set this if you want SRM to do DNS resolution internally, as opposed to relying on your system's default DNS server. This solves many timeout issues on the Steam Deck.

### Batch size for image downloads
Number of images SRM will attempt to download at once when saving to Steam. May help to lower this if you are receiving timeout errors from SGDB.
### Nuke artwork choice cache
SRM attempts to remember your artwork choices, this button forcibly forgets all of them.
### Nuke local artwork backups
This deletes all artwork backups created for parsers with `Backup artwork locally` enabled.
## Community Variables and Presets
### Force download custom variables.
Resets the custom variables JSON file that is used for certain presets to whatever its current state is on the SRM github. Useful if the custom variables JSON file has been corrupted.
### Force download custom presets.
Resets the JSON files for parser presets to whatever is on the SRM github. Useful if your presets list is not automatically updating for some reason, or has become corrupted.
### Force download shell scripts
Re fetches the shell scripts SRM uses to perform certain tasks.
43 changes: 36 additions & 7 deletions src/lib/helpers/steam/stop-start-steam.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { spawn, execSync } from "child_process";
import * as os from "os";
import { AppSettings } from "../../../models";
import { LoggerService } from "../../../renderer/services";

const checkDelay = 500;
const timeout = 5000;
const timeout = 10000;

interface ActAndCheck {
commands: {
Expand All @@ -16,7 +18,8 @@ interface ActAndCheck {
precheckPassed: string
},
checkOutput: string,
shell: string
shell: string,
safetyDelay: number
}

async function actAndCheck(data: ActAndCheck) {
Expand All @@ -38,9 +41,12 @@ async function actAndCheck(data: ActAndCheck) {
const interval: NodeJS.Timer = setInterval(() => {
const check = execSync(data.commands.check, {shell: data.shell}).toString().trim()
if(check == data.checkOutput){
messages.push(data.messages.success.interpolate({elapsed}))
clearTimeout(interval)
resolve({acted: true, messages: messages});
setTimeout(()=> {
clearTimeout(interval)
messages.push(data.messages.success.interpolate({elapsed: elapsed + data.safetyDelay}))
resolve({acted: true, messages: messages});

}, data.safetyDelay)
}
if(elapsed > timeout) {
reject(data.messages.failure.interpolate({timeout}))
Expand All @@ -64,22 +70,26 @@ export async function stopSteam() {
precheckPassed: "Steam is not running, no need to kill it."
},
checkOutput: 'True',
shell: 'powershell'
safetyDelay: 2000,
shell: null
}
if (os.type() == 'Windows_NT') {
data.commands = {
action: `wmic process where "name='steam.exe'" delete`,
check: `(Get-Process steam -ErrorAction SilentlyContinue) -eq $null`
}
data.shell = 'powershell'
} else if (os.type() == 'Linux') {
data.commands = {
action: `killall steam`,
check: `echo "True"`
}
data.shell = '/bin/sh'
}
return await actAndCheck(data);
}

//try to restart steam
export async function startSteam() {
let data: ActAndCheck = {
commands: null,
Expand All @@ -90,18 +100,37 @@ export async function startSteam() {
precheckPassed: "Steam is already running, no need to start it."
},
checkOutput: 'True',
shell: 'powershell'
safetyDelay: 0,
shell: null,

};
if (os.type() == 'Windows_NT') {
data.commands = {
action: "Start-Process -WindowStyle Minimized ${env:PROGRAMFILES(x86)}\\Steam\\steam.exe -ArgumentList \"-silent\"",
check: `(Get-Process steam -ErrorAction SilentlyContinue) -ne $null`
}
data.shell = 'powershell';
} else if (os.type() == 'Linux') {
data.commands = {
action: `start steam`,
check: `echo "True"`
}
data.shell = '/bin/sh'
}
return await actAndCheck(data)
}

export async function performSteamlessTask(appSettings: AppSettings, loggerService: LoggerService, task: () => Promise<void>) {
let stop: { acted: boolean, messages: string[] };
if(appSettings.autoKillSteam) {
loggerService.info('Attempting to kill Steam', {invokeAlert: true, alertTimeout: 3000})
stop = await stopSteam();
for(let message of stop.messages) { loggerService.info(message) }
}
await task();
if(appSettings.autoRestartSteam && stop.acted) {
loggerService.info('Attempting to restart Steam', {invokeAlert: true, alertTimeout: 3000})
const start = await startSteam();
for(let message of start.messages) { loggerService.info(message) }
}
}
4 changes: 3 additions & 1 deletion src/models/settings.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,7 @@ export interface AppSettings {
dnsServers: string[],
previewSettings: PreviewSettings,
navigationWidth: number,
clearLogOnTest: boolean
clearLogOnTest: boolean,
autoKillSteam: boolean,
autoRestartSteam: boolean
}
17 changes: 12 additions & 5 deletions src/renderer/components/ng-toggle-button.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
@Component({
selector: 'ng-toggle-button',
template: `
<div *ngIf="!contentOnLeft" class="button" style="margin-right: 0.25em;">
<div (click)="writeValue(!currentValue)" class="slider round" [class.active]="currentValue"></div>
<div *ngIf="!contentOnLeft" class="button" style="margin-right: 0.25em;" [class.disabled]="_disabled">
<div (click)="!_disabled ? writeValue(!currentValue) : null" class="slider round" [class.disabled]="_disabled"
[class.active]="currentValue"></div>
</div>
<div class="content">
<ng-content></ng-content>
</div>
<div *ngIf="contentOnLeft" class="button" style="margin-left: 0.25em;">
<div (click)="writeValue(!currentValue)" class="slider round" [class.active]="currentValue"></div>
<div *ngIf="contentOnLeft" class="button" style="margin-left: 0.25em;" [class.disabled]="_disabled">
<div (click)="!_disabled ? writeValue(!currentValue) : null" class="slider round" [class.disabled]="_disabled"
[class.active]="currentValue"></div>
</div>
`,
styleUrls: [
Expand All @@ -25,12 +27,17 @@ import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
})
export class NgToggleButtonComponent implements ControlValueAccessor {
@Input('contentOnLeft') contentOnLeft: boolean;

currentValue: boolean = false;
_disabled: boolean = false;
private onChange = (_: any) => { };
private onTouched = () => { };

constructor(private changeRef: ChangeDetectorRef) { }
@Input()
set disabled(value: boolean) {
this._disabled = value;
this.writeValue(false);
};

@Input()
set value(value: boolean) {
Expand Down
12 changes: 7 additions & 5 deletions src/renderer/components/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,14 @@ export class SettingsComponent implements OnDestroy {
}

async removeCategoriesOnly() {
for(let steamDir of this.knownSteamDirectories) {
const accounts = await steam.getAvailableLogins(steamDir);
for(let account of accounts) {
await this.previewService.removeCategories(steamDir, account.accountID)
await steam.performSteamlessTask(this.settingsService.getSettings(), this.loggerService, async () => {
for(let steamDir of this.knownSteamDirectories) {
const accounts = await steam.getAvailableLogins(steamDir);
for(let account of accounts) {
await this.previewService.removeCategories(steamDir, account.accountID)
}
}
}
})
}

async removeControllersOnly() {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/schemas/app-settings.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export const appSettings = {
autoUpdate: {type: 'boolean', default: true},
offlineMode: { type: 'boolean', default: false },
navigationWidth: { type: 'number', default: 0 },
clearLogOnTest: { type: 'boolean', default: false }
clearLogOnTest: { type: 'boolean', default: false },
autoKillSteam: { type: 'boolean', default: false },
autoRestartSteam: { type: 'boolean', default: false }
}
};
21 changes: 6 additions & 15 deletions src/renderer/services/preview.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,8 @@ export class PreviewService {

async removeCategories(steamDir: string, userId: string) {
try {
const stop = await steam.stopSteam();
for(let message of stop.messages) { this.loggerService.info(message) }
this.loggerService.info(`Removing category information for user ${userId}.`);
await this.categoryManager.removeAllCategoriesAndWrite(steamDir, userId);
if(stop.acted) {
const start= await steam.startSteam();
for(let message of start.messages) { this.loggerService.info(message) }
}
} catch(error) {
this.loggerService.error(this.lang.errors.categorySaveError, { invokeAlert: true, alertTimeout: 3000 });
this.loggerService.error(this.lang.errors.categorySaveError__i.interpolate({error:error.message}));
Expand Down Expand Up @@ -224,14 +219,10 @@ export class PreviewService {
})
.then(async () => {
if(!removeAll && !this.appSettings.previewSettings.disableCategories) {
const stop = await steam.stopSteam();
for(let message of stop.messages) { this.loggerService.info(message) }
this.loggerService.info(this.lang.info.savingCategories)
await this.categoryManager.save(this.previewData, exAppIds, addedCats)
if(stop.acted) {
const start= await steam.startSteam();
for(let message of start.messages) { this.loggerService.info(message) }
}
await steam.performSteamlessTask(this.appSettings, this.loggerService, async () => {
this.loggerService.info(this.lang.info.savingCategories);
await this.categoryManager.save(this.previewData, exAppIds, addedCats)
})
}
}).catch((error: Acceptable_Error | Error) => {
if(error instanceof Acceptable_Error) {
Expand Down Expand Up @@ -500,7 +491,7 @@ export class PreviewService {
this.loggerService.info(this.lang.info.noAccountsWarning, { invokeAlert: true, alertTimeout: 3000 });
}
else {
if(!this.appSettings.previewSettings.disableCategories){
if(!this.appSettings.previewSettings.disableCategories && !this.appSettings.autoKillSteam){
this.loggerService.info(this.lang.info.shutdownSteam, { invokeAlert: true, alertTimeout: 3000 });
}
previewData = await this.createPreviewData(data.parsedData.parsedConfigs);
Expand Down
16 changes: 4 additions & 12 deletions src/renderer/services/view.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { LoggerService, ParsersService } from '../services';
import { LoggerService, ParsersService, SettingsService } from '../services';
import { VDF_ListData, ControllerTemplates, ControllerTemplate, SteamList, VDF_ListItem, SteamDirList } from '../../models';
import * as _ from "lodash";
import {
Expand All @@ -9,7 +9,6 @@ import {
} from "../../lib";
import { controllerTypes } from '../../lib/controller-manager';
import { BehaviorSubject } from 'rxjs';
import * as steam from '../../lib/helpers/steam';

@Injectable()
export class ViewService {
Expand All @@ -35,7 +34,7 @@ export class ViewService {
}
constructor(
private parsersService: ParsersService,
private loggerService: LoggerService
private loggerService: LoggerService,
) {
}

Expand All @@ -50,22 +49,21 @@ export class ViewService {
this.clearData();
this.status.refreshingShortcuts.next(true);
this.status.refreshingDetails.next(true);
let knownSteamDirectories = this.parsersService.getKnownSteamDirectories();
const knownSteamDirectories = this.parsersService.getKnownSteamDirectories();
const vdfManager = new VDF_Manager();
const categoryManager = new CategoryManager();
const controllerManager = new ControllerManager();
await vdfManager.prepare(knownSteamDirectories);
await vdfManager.read({ addedItems: false });
this.vdfData = vdfManager.vdfData;
this.status.refreshingShortcuts.next(false);
const stop = await steam.stopSteam();
for(let message of stop.messages) { this.loggerService.info(message) }
for(const steamDirectory in this.vdfData) {
this.categoryData[steamDirectory] = {};
this.controllerData[steamDirectory] = {};
this.controllerTemplateData[steamDirectory] = {};
for(const userId in this.vdfData[steamDirectory]) {
try {
this.loggerService.info(`Reading category information for user ${userId} (View Games).`);
this.categoryData[steamDirectory][userId] = await categoryManager.readCategories(steamDirectory, userId);
} catch (e) {}
const configsetDir = ControllerManager.configsetDir(steamDirectory, userId);
Expand All @@ -79,12 +77,6 @@ export class ViewService {
this.controllerTemplateData[steamDirectory][controllerType] = await ControllerManager.readTemplates(steamDirectory, controllerType)
}
}
if(stop.acted) {
const start= await steam.startSteam();
for(let message of start.messages) { this.loggerService.info(message) }
}

await steam.startSteam();
this.status.refreshingDetails.next(false);
}
}
6 changes: 4 additions & 2 deletions src/renderer/styles/ng-toggle-button.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
width: calc(var(--ng-toggle-button-height) * var(--ng-toggle-button-width-ratio));
height: var(--ng-toggle-button-height);
margin: var(--ng-toggle-middle-button-size-increment);

& .disabled {
opacity: 0.3;
}
.slider {
position: absolute;
cursor: pointer;
Expand Down Expand Up @@ -83,7 +85,7 @@
border-color: var(--ng-toggle-button-color-button-border);
}

&:hover{
&:hover:not(.disabled) {
background-color: var(--ng-toggle-button-color-fill-hover);
border-color: var(--ng-toggle-button-color-border-hover);

Expand Down
5 changes: 5 additions & 0 deletions src/renderer/templates/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
</div>
<div class="inputContainer">
<ng-toggle-button class="ngToggleButton" [ngModel]="settings.autoUpdate" (ngModelChange)="settings.autoUpdate = $event; onSettingsChange();">{{lang.text.autoUpdate}}</ng-toggle-button>
<ng-toggle-button class="ngToggleButton" [ngModel]="settings.autoKillSteam" (ngModelChange)="settings.autoKillSteam = $event; onSettingsChange()">Auto kill Steam</ng-toggle-button>
<ng-toggle-button class="ngToggleButton"
[ngModel]="settings.autoRestartSteam"
[disabled]="!settings.autoKillSteam"
(ngModelChange)="settings.autoRestartSteam = $event; onSettingsChange()">Auto restart Steam</ng-toggle-button>
<ng-toggle-button class="ngToggleButton" [ngModel]="settings.offlineMode" (ngModelChange)="settings.offlineMode = $event; onSettingsChange();">{{lang.text.offlineMode}}</ng-toggle-button>
<ng-toggle-button class="ngToggleButton" [ngModel]="settings.clearLogOnTest" (ngModelChange)="settings.clearLogOnTest = $event; onSettingsChange();">{{lang.text.clearLogOnTest}}</ng-toggle-button>
</div>
Expand Down

0 comments on commit 31a2a40

Please sign in to comment.