Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"classnames": "^2.2.6",
"clean-webpack-plugin": "^3.0.0",
"colors": "^1.4.0",
"crc": "^4.3.2",
"crc-32": "^1.2.0",
"fast-memoize": "^2.5.2",
"intl-messageformat": "^9.4.6",
Expand Down Expand Up @@ -66,6 +67,7 @@
"shell-quote": "^1.7.2",
"source-map-support": "^0.5.19",
"split2": "^3.2.2",
"steam-shortcut-editor": "^3.1.3",
"styled-components": "^5.2.1",
"systeminformation": "^5.21.7",
"term-color": "^1.0.1",
Expand All @@ -79,6 +81,7 @@
"yauzl": "^2.9.2"
},
"devDependencies": {
"@electron/notarize": "^2.3.2",
"@itchio/bob": "^2.1.0",
"@types/classnames": "^2.2.11",
"@types/clone": "^2.1.0",
Expand Down Expand Up @@ -110,7 +113,6 @@
"cross-env": "^7.0.3",
"css-loader": "^5.2.4",
"electron": "^22.3.27",
"@electron/notarize": "^2.3.2",
"electron-packager": "^17.1.2",
"file-loader": "^6.2.0",
"happypack": "^5.0.1",
Expand Down Expand Up @@ -196,7 +198,8 @@
"split2",
"log-rotate",
"butlerd",
"querystring"
"querystring",
"steam-shortcut-editor"
],
"renderer": {
"webpackConfig": "custom.webpack.additions.js"
Expand All @@ -209,4 +212,4 @@
]
}
}
}
}
1 change: 1 addition & 0 deletions src/common/reducers/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const initialState = {
preferOptimizedPatches: false,
disableBrowser: env.integrationTests ? true : false,
enableTabs: false,
addGamesToSteam: false,
} as PreferencesState;

export default reducer<PreferencesState>(initialState, (on) => {
Expand Down
3 changes: 3 additions & 0 deletions src/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ export interface PreferencesState {

/** whether or not we've already imported appdata as an install location */
importedOldInstallLocations: boolean;

/** whether games should be added to steam automatically */
addGamesToSteam: boolean;
}

export interface Task {
Expand Down
2 changes: 1 addition & 1 deletion src/main/reactors/context-menu/build-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,5 @@ export function userMenu(store: Store): MenuTemplate {
function escapeForContextMenu(label: string) {
// In a context menu, '&[^&]' will be interpreted as a shortcut
// definition. Escaping requires a second ampersand
return label.replaceAll("&", "&&");
return label.replace("&", "&&");
}
13 changes: 13 additions & 0 deletions src/main/reactors/downloads/download-ended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Watcher } from "common/util/watcher";
import { actions } from "common/actions";
import { t } from "common/format/t";
import { urlForGame } from "common/util/navigation";
import { addGameToSteam } from "main/steam";

export default function (watcher: Watcher) {
watcher.on(actions.downloadEnded, async (store, action) => {
Expand Down Expand Up @@ -58,5 +59,17 @@ export default function (watcher: Watcher) {
);
}
}

// Add game to Steam if the option is enabled and this is an install
if (download.reason === "install") {
console.log("Download ended for install, checking Steam integration...");
try {
const result = await addGameToSteam(store, download.game);
console.log("Steam integration result:", result);
} catch (error) {
console.error("Failed to add game to Steam:", error);
console.error("Error stack:", error.stack);
}
}
});
}
12 changes: 12 additions & 0 deletions src/main/reactors/downloads/perform-uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as messages from "common/butlerd/messages";
import { Logger } from "common/logger";
import { Store } from "common/types";
import { mcall } from "main/butlerd/mcall";
import { removeGameFromSteam } from "main/steam";

export async function performUninstall(
store: Store,
Expand All @@ -23,4 +24,15 @@ export async function performUninstall(
});
});
logger.info(`Uninstall successful`);

// Remove game from Steam after successful uninstall
try {
const cave = await mcall(messages.FetchCave, { caveId });
if (cave.cave && cave.cave.game) {
await removeGameFromSteam(store, cave.cave.game);
logger.info(`Removed ${cave.cave.game.title} from Steam`);
}
} catch (error) {
logger.warn(`Failed to remove game from Steam: ${error}`);
}
}
9 changes: 9 additions & 0 deletions src/main/reactors/tasks/queue-cave-uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { performUninstall } from "main/reactors/downloads/perform-uninstall";
import { promisedModal } from "main/reactors/modals";
import asTask from "main/reactors/tasks/as-task";
import { mcall } from "main/butlerd/mcall";
import { removeGameFromSteam } from "main/steam";

const logger = mainLogger.child(__filename);

Expand Down Expand Up @@ -42,6 +43,14 @@ export default function (watcher: Watcher) {
});
logger.info(`Uninstall successful`);

// Remove game from Steam after successful uninstall
try {
await removeGameFromSteam(store, cave.game);
logger.info(`Removed ${cave.game.title} from Steam`);
} catch (error) {
logger.warn(`Failed to remove game from Steam: ${error}`);
}

store.dispatch(actions.uninstallEnded({}));
},
onError: async (e, log) => {
Expand Down
97 changes: 97 additions & 0 deletions src/main/steam/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Game } from "common/butlerd/messages";
import { Store } from "common/types";
import { addNonSteamGame } from "./steam-shortcuts";
import { mainLogger } from "main/logger";

const logger = mainLogger.child(__filename);

export interface SteamGameInfo {
title: string;
app_name: string;
runner: string;
art_cover?: string;
art_square?: string;
art_logo?: string;
}

export async function removeGameFromSteam(
store: Store,
game: Game
): Promise<boolean> {
const prefs = store.getState().preferences;

if (!prefs.addGamesToSteam) {
return false;
}

logger.info(`Attempting to remove ${game.title} from Steam`);

const gameInfo: SteamGameInfo = {
title: game.title,
app_name: game.id.toString(),
runner: "itch",
art_cover: game.coverUrl,
art_square: game.stillCoverUrl,
};

try {
const { removeNonSteamGame } = await import("./steam-shortcuts");
const success = await removeNonSteamGame({ gameInfo });
if (success) {
logger.info(`Successfully removed ${game.title} from Steam`);
} else {
logger.warn(`Failed to remove ${game.title} from Steam`);
}
return success;
} catch (error) {
logger.error(`Error removing ${game.title} from Steam:`);
logger.error(error);
return false;
}
}

export async function addGameToSteam(
store: Store,
game: Game
): Promise<boolean> {
console.log("addGameToSteam called for:", game.title);
const prefs = store.getState().preferences;
console.log("Steam integration preference:", prefs.addGamesToSteam);

if (!prefs.addGamesToSteam) {
console.log("Steam integration disabled in preferences");
logger.debug("Steam integration disabled in preferences");
return false;
}

console.log(`Attempting to add ${game.title} to Steam`);
logger.info(`Attempting to add ${game.title} to Steam`);

const gameInfo: SteamGameInfo = {
title: game.title,
app_name: game.id.toString(),
runner: "itch",
art_cover: game.coverUrl,
art_square: game.stillCoverUrl,
};

console.log("Game info:", gameInfo);

try {
const success = await addNonSteamGame({ gameInfo });
console.log("addNonSteamGame result:", success);
if (success) {
console.log(`Successfully added ${game.title} to Steam`);
logger.info(`Successfully added ${game.title} to Steam`);
} else {
console.log(`Failed to add ${game.title} to Steam`);
logger.warn(`Failed to add ${game.title} to Steam`);
}
return success;
} catch (error) {
console.error(`Error adding ${game.title} to Steam:`, error);
logger.error(`Error adding ${game.title} to Steam:`);
logger.error(error);
return false;
}
}
Loading