-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ddbe550
Showing
12 changed files
with
1,001 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
/lib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
language: node_js | ||
node_js: '10' | ||
cache: yarn | ||
|
||
script: | ||
- yarn build | ||
- yarn lint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# find-steam-app | ||
|
||
> Find location of an installed Steam app | ||
## Usage | ||
|
||
```js | ||
import { | ||
findSteam, | ||
findSteamAppById, | ||
findSteamAppByName, | ||
findSteamAppManifest, | ||
findSteamLibraries, | ||
} from 'find-steam-app'; | ||
|
||
await findSteamAppById(570); | ||
// => '/path/to/steam/steamapps/common/dota 2 beta' | ||
|
||
await findSteamAppByName('dota 2 beta'); | ||
// => '/path/to/steam/steamapps/common/dota 2 beta' | ||
|
||
await findSteam(); | ||
// => '/path/to/steam' | ||
|
||
await findSteamLibraries(); | ||
// => ['/path/to/steam/steamapps', '/path/to/library/steamapps'] | ||
|
||
await findSteamAppManifest(570); | ||
// => { appid: 570, Universe: 1, name: 'Dota 2', ... } | ||
``` | ||
|
||
For more information about manifest, see [manifest.ts](src/manifest.ts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"name": "find-steam-app", | ||
"version": "1.0.0", | ||
"description": "Find location of an installed Steam app", | ||
"keywords": [ | ||
"app", | ||
"appid", | ||
"search", | ||
"steam", | ||
"valve" | ||
], | ||
"repository": "https://github.com/ark120202/find-steam-app", | ||
"license": "MIT", | ||
"author": "ark120202", | ||
"files": [ | ||
"lib" | ||
], | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"scripts": { | ||
"build": "tsc", | ||
"dev": "tsc --watch", | ||
"lint": "tslint -p .", | ||
"prepublishOnly": "yarn build" | ||
}, | ||
"prettier": { | ||
"printWidth": 100, | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
}, | ||
"dependencies": { | ||
"execa": "^1.0.0", | ||
"fs-extra": "^7.0.1", | ||
"p-filter": "^1.0.0", | ||
"tslib": "^1.9.3", | ||
"vdf-extra": "^2.2.2" | ||
}, | ||
"devDependencies": { | ||
"@ark120202/tslint-config": "^2.1.1", | ||
"@ark120202/typescript-config": "^1.4.2", | ||
"@types/execa": "^0.9.0", | ||
"@types/fs-extra": "^5.0.4", | ||
"prettier": "^1.15.3", | ||
"tslint": "^5.12.1", | ||
"tslint-plugin-prettier": "^2.0.1", | ||
"typescript": "^3.2.2", | ||
"typescript-tslint-plugin": "^0.2.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import fs from 'fs-extra'; | ||
import pFilter from 'p-filter'; | ||
import path from 'path'; | ||
import { loadSteamLibraries } from './libraries'; | ||
import { AppManifest, hasManifest, readManifest } from './manifest'; | ||
import { findSteam } from './steam'; | ||
|
||
export { AppManifest, findSteam }; | ||
|
||
export class SteamNotFoundError extends Error { | ||
public constructor() { | ||
super('Steam installation directory not found'); | ||
this.name = 'SteamNotFoundError'; | ||
} | ||
} | ||
|
||
/** | ||
* Searches for all local Steam libraries. | ||
* | ||
* @returns Array of paths to library folders. | ||
*/ | ||
export async function findSteamLibraries() { | ||
const steam = await findSteam(); | ||
if (steam == null) throw new SteamNotFoundError(); | ||
|
||
return loadSteamLibraries(steam); | ||
} | ||
|
||
/** | ||
* Searches for app in local Steam libraries. | ||
* | ||
* @returns Information about installed application. | ||
*/ | ||
export async function findSteamAppManifest(appId: number) { | ||
const libs = await findSteamLibraries(); | ||
const [library] = await pFilter(libs, lib => hasManifest(lib, appId)); | ||
if (library == null) return; | ||
|
||
return readManifest(library, appId); | ||
} | ||
|
||
/** | ||
* Searches for app in local Steam libraries. | ||
* | ||
* @returns Path to installed app. | ||
*/ | ||
export async function findSteamAppByName(name: string) { | ||
const libs = await findSteamLibraries(); | ||
const [library] = await pFilter(libs, lib => fs.pathExists(path.join(lib, 'common', name))); | ||
if (library == null) return; | ||
|
||
return path.join(library, 'common', name); | ||
} | ||
|
||
/** | ||
* Searches for app in local Steam libraries. | ||
* | ||
* @returns Path to installed app. | ||
*/ | ||
export async function findSteamAppById(appId: number) { | ||
const libs = await findSteamLibraries(); | ||
const [library] = await pFilter(libs, lib => hasManifest(lib, appId)); | ||
if (library == null) return; | ||
|
||
const manifest = await readManifest(library, appId); | ||
return path.join(library, 'common', manifest.installdir); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import fs from 'fs-extra'; | ||
import path from 'path'; | ||
import vdf from 'vdf-extra'; | ||
|
||
interface LibraryFolders { | ||
TimeNextStatsReport: string; | ||
ContentStatsID: string; | ||
[id: string]: string; | ||
} | ||
|
||
export async function loadSteamLibraries(steam: string) { | ||
const mainSteamApps = path.join(steam, 'steamapps'); | ||
const libraryFoldersPath = path.join(mainSteamApps, 'libraryfolders.vdf'); | ||
const libraryFoldersContent = await fs.readFile(libraryFoldersPath, 'utf8'); | ||
const libraryFoldersData = vdf.parse<LibraryFolders>(libraryFoldersContent); | ||
|
||
const libraries = Object.entries(libraryFoldersData) | ||
.filter(([id]) => !isNaN(Number(id))) | ||
.map(([, libPath]) => path.join(libPath, 'steamapps')); | ||
|
||
return [mainSteamApps, ...libraries]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import fs from 'fs-extra'; | ||
import path from 'path'; | ||
import vdf from 'vdf-extra'; | ||
|
||
export interface AppManifest { | ||
appid: number; | ||
Universe: number; | ||
name: string; | ||
StateFlags: number; | ||
installdir: string; | ||
LastUpdated: number; | ||
UpdateResult: 0 | 1; | ||
SizeOnDisk: number; | ||
buildid: number; | ||
LastOwner: string; | ||
BytesToDownload: number; | ||
BytesDownloaded: number; | ||
AutoUpdateBehavior: 0 | 1; | ||
AllowOtherDownloadsWhileRunning: 0 | 1; | ||
ScheduledAutoUpdate: number; | ||
UserConfig: { | ||
language: string; | ||
DisabledDLC?: string; | ||
optionaldlc?: string; | ||
}; | ||
InstalledDepots: Record<string, { manifest: string; dlcappid?: number }>; | ||
MountedDepots: Record<string, string>; | ||
InstallScripts?: Record<string, string>; | ||
ShaderDepot?: { | ||
ManifestID: string; | ||
DepotSize: number; | ||
}; | ||
} | ||
|
||
export async function hasManifest(library: string, appid: number) { | ||
return fs.pathExists(path.join(library, `appmanifest_${appid}.acf`)); | ||
} | ||
|
||
export async function readManifest(library: string, appid: number) { | ||
const manifestPath = path.join(library, `appmanifest_${appid}.acf`); | ||
const manifestContent = await fs.readFile(manifestPath, 'utf8'); | ||
const manifestData = vdf.parse<AppManifest>(manifestContent); | ||
|
||
return manifestData; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import execa from 'execa'; | ||
import fs from 'fs-extra'; | ||
import path from 'path'; | ||
|
||
const pathIfExists = async (name: string) => ((await fs.pathExists(name)) ? name : undefined); | ||
const getRegExePath = () => | ||
process.platform === 'win32' && process.env.windir != null | ||
? path.join(process.env.windir, 'System32', 'reg.exe') | ||
: 'REG'; | ||
|
||
const REG_TREE_PATH = 'HKCU\\Software\\Valve\\Steam'; | ||
const REG_KEY_NOT_FOUND = 'The system was unable to find the specified registry key or value'; | ||
async function windows() { | ||
let programFiles = process.env['ProgramFiles(x86)']; | ||
if (programFiles == null) programFiles = process.env.ProgramFiles; | ||
if (programFiles != null && (await fs.pathExists(`${programFiles}/Steam/Steam.exe`))) { | ||
return `${programFiles}/Steam`; | ||
} | ||
|
||
try { | ||
const output = await execa.stdout( | ||
getRegExePath(), | ||
['QUERY', REG_TREE_PATH, '/v', 'SteamPath'], | ||
{ cwd: undefined }, | ||
); | ||
const matches = output.match(/SteamPath\s+[A-Z_]+\s+(.+)/); | ||
if (!matches || !matches[1]) throw new Error(`Unexpected output:\n${output.trim()}`); | ||
|
||
return pathIfExists(matches[1]); | ||
} catch (err) { | ||
if (!err.message.includes(REG_KEY_NOT_FOUND)) { | ||
throw err; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Searches for Steam. | ||
* | ||
* @returns Location of Steam. `undefined` if Steam wasn't found. | ||
*/ | ||
export async function findSteam() { | ||
switch (process.platform) { | ||
case 'win32': | ||
return windows(); | ||
case 'linux': | ||
return pathIfExists(`${process.env.HOME}/.local/share/Steam`); | ||
case 'darwin': | ||
return pathIfExists(`${process.env.HOME}/Library/Application Support/Steam`); | ||
default: | ||
throw new Error(`Steam finding isn't implemented for ${process.platform}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
declare module 'p-filter' { | ||
function pFilter<T>( | ||
iterable: Iterable<T | Promise<T>>, | ||
filterer: (element: T, index: number) => boolean | Promise<boolean>, | ||
): Promise<T[]>; | ||
|
||
export = pFilter; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "@ark120202/typescript-config/node10.json", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./lib" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": ["@ark120202/tslint-config", "@ark120202/tslint-config/prettier"] | ||
} |
Oops, something went wrong.