2025-11-25 22:16:39 -06:00
|
|
|
import { writeFile } from "fs/promises";
|
2025-11-25 22:20:46 -06:00
|
|
|
import { normalize } from "path";
|
2025-11-25 22:14:09 -06:00
|
|
|
import SteamUser, { EConnectionProtocol } from "steam-user";
|
2025-11-25 21:37:31 -06:00
|
|
|
|
2025-11-25 22:16:39 -06:00
|
|
|
interface SteamManifestFile {
|
|
|
|
|
chunks: {
|
|
|
|
|
sha: string;
|
|
|
|
|
crc: number;
|
|
|
|
|
offset: string;
|
|
|
|
|
cb_original: number;
|
|
|
|
|
cb_compressed: number;
|
2025-11-25 22:14:09 -06:00
|
|
|
}[];
|
2025-11-25 22:16:39 -06:00
|
|
|
filename: string;
|
|
|
|
|
size: string;
|
|
|
|
|
flags: number;
|
|
|
|
|
sha_filename: string;
|
|
|
|
|
sha_content: string;
|
|
|
|
|
linktarget: unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface SteamManifest {
|
|
|
|
|
files: SteamManifestFile[];
|
2025-11-25 22:20:46 -06:00
|
|
|
depot_id: number;
|
|
|
|
|
gid_manifest: string;
|
|
|
|
|
creation_time: number;
|
|
|
|
|
filenames_encrypted: boolean;
|
|
|
|
|
cb_disk_original: string;
|
|
|
|
|
cb_disk_compressed: string;
|
|
|
|
|
unique_chunks: number;
|
|
|
|
|
crc_encrypted: number;
|
|
|
|
|
crc_clear: number;
|
2025-11-25 22:14:09 -06:00
|
|
|
}
|
2025-11-25 21:37:31 -06:00
|
|
|
|
2025-11-25 22:14:09 -06:00
|
|
|
export class SteamVFS {
|
|
|
|
|
private steam = new SteamUser({ protocol: EConnectionProtocol.TCP });
|
|
|
|
|
|
2025-11-25 22:16:39 -06:00
|
|
|
private manifest: Map<string, SteamManifestFile> = new Map();
|
2025-11-25 22:14:09 -06:00
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
|
private username: string,
|
|
|
|
|
private password: string,
|
|
|
|
|
private app: number,
|
|
|
|
|
private depot: number
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
async init() {
|
|
|
|
|
this.steam.logOn({
|
|
|
|
|
accountName: this.username,
|
|
|
|
|
password: this.password,
|
2025-11-25 21:37:31 -06:00
|
|
|
});
|
|
|
|
|
|
2025-11-25 22:14:09 -06:00
|
|
|
await new Promise((resolve) => this.steam.once("loggedOn", resolve));
|
2025-11-25 21:37:31 -06:00
|
|
|
|
2025-11-25 22:14:09 -06:00
|
|
|
const productInfo = await this.steam.getProductInfo([this.app], []);
|
2025-11-25 22:16:39 -06:00
|
|
|
const manifest: SteamManifest = await new Promise((resolve) => {
|
2025-11-25 22:14:09 -06:00
|
|
|
this.steam.getManifest(
|
|
|
|
|
this.app,
|
|
|
|
|
this.depot,
|
|
|
|
|
productInfo.apps[this.app].appinfo.depots[this.depot].manifests.public
|
|
|
|
|
.gid,
|
|
|
|
|
"public",
|
|
|
|
|
(_, response) => {
|
|
|
|
|
resolve(response);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
2025-11-25 22:20:46 -06:00
|
|
|
let str = "";
|
2025-11-25 22:16:39 -06:00
|
|
|
for (const file of manifest.files) {
|
2025-11-25 22:20:46 -06:00
|
|
|
const path = normalize(file.filename);
|
|
|
|
|
str += `${path}\n`;
|
|
|
|
|
this.manifest.set(path, file);
|
2025-11-25 22:16:39 -06:00
|
|
|
}
|
|
|
|
|
|
2025-11-25 22:20:46 -06:00
|
|
|
writeFile("test.txt", str);
|
2025-11-25 22:16:39 -06:00
|
|
|
|
2025-11-25 22:14:09 -06:00
|
|
|
console.log(JSON.stringify(manifest.files[0], null, 2));
|
2025-11-25 21:37:31 -06:00
|
|
|
}
|
|
|
|
|
}
|