steamutils 1.5.51 → 1.5.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import path from "path";
2
2
  import { fileURLToPath } from "url";
3
3
  import Protobuf from "protobufjs";
4
+ import gpf from "google-proto-files";
4
5
 
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = path.dirname(__filename);
@@ -11,10 +12,14 @@ export class SteamProto {
11
12
  }
12
13
 
13
14
  toProto() {
14
- const root = new Protobuf.Root().loadSync(path.join(`${__dirname}/protos/`, this._proto.filename), {
15
+ const localProto = path.join(`${__dirname}/protos/`, this._proto.filename);
16
+
17
+ const descriptorPath = gpf.getProtoPath("protobuf/descriptor.proto");
18
+
19
+ const root = new Protobuf.Root().loadSync([descriptorPath, localProto], {
15
20
  keepCase: true,
16
21
  });
17
- return root[this._proto.name];
22
+ return root.lookupType(this._proto.name);
18
23
  }
19
24
 
20
25
  protoEncode(obj) {
package/index.js CHANGED
@@ -7291,6 +7291,39 @@ export default class SteamUser {
7291
7291
  };
7292
7292
  }
7293
7293
 
7294
+ /**
7295
+ * @typedef {Object} FriendGameplayInfoEntry
7296
+ * @property {string} steamId - The SteamID64 of the friend.
7297
+ * @property {number} minutes_played - Number of minutes played recently or currently.
7298
+ * @property {number} minutes_played_forever - Total minutes this friend has played forever.
7299
+ */
7300
+
7301
+ /**
7302
+ * @typedef {Object} YourInfo
7303
+ * @property {number} minutes_played - Number of minutes you have played recently or currently.
7304
+ * @property {number} minutes_played_forever - Total minutes you have played forever.
7305
+ * @property {boolean} in_wishlist - Whether the app is in your wishlist.
7306
+ * @property {boolean} owned - Whether you own the app.
7307
+ */
7308
+
7309
+ /**
7310
+ * @typedef {Object} FriendsGameplayInfoResponse
7311
+ * @property {FriendGameplayInfoEntry[]} in_game - Friends currently playing the game.
7312
+ * @property {FriendGameplayInfoEntry[]} played_recently - Friends who played the game recently.
7313
+ * @property {FriendGameplayInfoEntry[]} played_ever - Friends who have ever played the game.
7314
+ * @property {FriendGameplayInfoEntry[]} owns - Friends who own the game.
7315
+ * @property {YourInfo} your_info - Information about your own playtime, wishlist and ownership for this app.
7316
+ */
7317
+
7318
+ /**
7319
+ * Retrieves Steam friends' gameplay stats for a specific app.
7320
+ *
7321
+ * @param {string} accessToken - Steam user access token.
7322
+ * @param {number|string} appId - The App ID of the game to query.
7323
+ * @returns {Promise<FriendsGameplayInfoResponse|undefined>}
7324
+ * Resolves with gameplay info: lists of friends (by status) and your stats for the app,
7325
+ * or `undefined` if the result is empty or on unauthorized access.
7326
+ */
7294
7327
  async getFriendsGameplayInfo(accessToken, appId) {
7295
7328
  if (!appId) {
7296
7329
  return;
@@ -7311,7 +7344,7 @@ export default class SteamUser {
7311
7344
  responseType: "arraybuffer",
7312
7345
  });
7313
7346
  if (result instanceof ResponseError) {
7314
- return result;
7347
+ return;
7315
7348
  }
7316
7349
 
7317
7350
  if (!result || result.status === 401) {
@@ -7339,45 +7372,6 @@ export default class SteamUser {
7339
7372
  owns: formatList(owns),
7340
7373
  your_info: _.omit(your_info, "steamid"),
7341
7374
  };
7342
-
7343
- const example = [
7344
- {
7345
- public_data: {
7346
- visibility_state: 3,
7347
- privacy_state: 0,
7348
- profile_state: 1,
7349
- ban_expires_time: 0,
7350
- account_flags: 0,
7351
- persona_name: "LOL haha",
7352
- profile_url: "",
7353
- content_country_restricted: false,
7354
- steamId: "76561199243542939",
7355
- avatarHash: "0000000000000000000000000000000000000000",
7356
- },
7357
- private_data: {
7358
- persona_state: 0,
7359
- persona_state_flags: 0,
7360
- time_created: 1644675779,
7361
- game_id: 0,
7362
- game_server_ip_address: 0,
7363
- game_server_port: 0,
7364
- game_extra_info: "",
7365
- account_name: "",
7366
- lobby_steam_id: 0,
7367
- rich_presence_kv: "",
7368
- watching_broadcast_accountid: 0,
7369
- watching_broadcast_appid: 0,
7370
- watching_broadcast_viewers: 0,
7371
- watching_broadcast_title: "",
7372
- last_logoff_time: 0,
7373
- last_seen_online: 0,
7374
- game_os_type: 0,
7375
- game_device_type: 0,
7376
- game_device_name: "",
7377
- game_is_private: false,
7378
- },
7379
- },
7380
- ];
7381
7375
  }
7382
7376
 
7383
7377
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "steamutils",
3
- "version": "1.5.51",
3
+ "version": "1.5.52",
4
4
  "main": "index.js",
5
5
  "dependencies": {
6
6
  "alpha-common-utils": "^1.0.6",
package/parse_html.js CHANGED
@@ -1,189 +1,189 @@
1
- import { StringUtils } from "alpha-common-utils/index.js";
2
- import { formatMarketHistoryDate } from "./utils.js";
3
- import * as cheerio from "cheerio";
4
-
5
- /**
6
- * @typedef {Object} HoverItem
7
- * @property {string|null} listingId The listing ID extracted from the selector, if available (as string).
8
- * @property {number} appid The app (game) ID for this item.
9
- * @property {number} contextid The context ID for this item.
10
- * @property {number} assetid The unique asset ID.
11
- * @property {string} unknown A string field captured from the arguments (usually "0").
12
- * @property {string} [name_selector] The HTML selector for the item's name, if present.
13
- * @property {string} [image_selector] The HTML selector for the item's image, if present.
14
- * @property {string} [other_selector] The selector string if it does not match name/image pattern.
15
- */
16
-
17
- /**
18
- * Extracts item information from Steam inventory trade history or similar HTML fragments.
19
- * Scans the given HTML string for calls to `CreateItemHoverFromContainer` and extracts
20
- * key data for each referenced item. Returns each item's info in a structured array.
21
- *
22
- * @param {string} html - The HTML string to parse.
23
- * @returns {HoverItem[]} Array of hover item objects.
24
- */
25
- export function extractAssetItemsFromHovers(html) {
26
- // Use your preferred HTML/space scrubber.
27
- html = StringUtils.cleanSpace(html);
28
-
29
- // RegExp for CreateItemHoverFromContainer arguments
30
- const re = /CreateItemHoverFromContainer\s*\(\s*g_rgAssets\s*,\s*'([^']+)'\s*,\s*(\d+)\s*,\s*'(\d+)'\s*,\s*'(\d+)'\s*,\s*(\d+)\s*\)/g;
31
-
32
- /** @type {Record<number, HoverItem>} */
33
- const itemsMap = {};
34
- let match;
35
-
36
- while ((match = re.exec(html)) !== null) {
37
- const [_, selector, appid, contextid, assetid, unknown] = match;
38
-
39
- // Extract listingId as a string if present: "history_row_<listingId>_"
40
- let listingId = null;
41
- const lidMatch = selector.match(/history_row_(\d+)_/);
42
- if (lidMatch) listingId = lidMatch[1]; // assign as string
43
-
44
- const appidNum = Number(appid);
45
- const contextidNum = Number(contextid);
46
- const assetidNum = Number(assetid);
47
-
48
- if (!itemsMap[assetidNum]) {
49
- itemsMap[assetidNum] = {
50
- listingId,
51
- appid: appidNum,
52
- contextid: contextidNum,
53
- assetid: assetidNum,
54
- unknown,
55
- };
56
- }
57
-
58
- if (selector.endsWith("_name")) {
59
- itemsMap[assetidNum].name_selector = selector;
60
- } else if (selector.endsWith("_image")) {
61
- itemsMap[assetidNum].image_selector = selector;
62
- } else {
63
- itemsMap[assetidNum].other_selector = selector;
64
- }
65
- }
66
- return Object.values(itemsMap);
67
- }
68
-
69
- /**
70
- * @typedef {Object} MarketHistoryListing
71
- * @property {string} id - HTML row id attribute (e.g. "history_row_4316182845737233773_4316182845737233774").
72
- * @property {string} listingId - Listing id (e.g. "4316182845737233773").
73
- * @property {number} price - Price in integer form (e.g. 80270).
74
- * @property {string} itemName - The market item's name (e.g. "UMP-45 | Mudder").
75
- * @property {string} gameName - The game's name (e.g. "Counter-Strike 2").
76
- * @property {string} listedOn - Listing date as string (e.g. "27 May 2024").
77
- * @property {string} actedOn - Acted on date or empty string.
78
- * @property {string} image - Full image URL for the item.
79
- * @property {string} gainOrLoss - "+" for buys, "-" for sells.
80
- * @property {string} status - Status text, usually empty string.
81
- * @property {string} [assetId] - (optional) Associated asset id, if available.
82
- */
83
-
84
- /**
85
- * Parses Steam market history listing rows into structured data objects.
86
- *
87
- * @param {string} html - The raw HTML string to parse.
88
- * @param {Object} [assetByListingId={}] - Optional mapping of listingId to assetId.
89
- * @returns {MarketHistoryListing[]} Array of market listing objects.
90
- */
91
- export function parseMarketHistoryListings(html, assetByListingId = {}) {
92
- const $ = cheerio.load(html);
93
- return $(".market_listing_row")
94
- .toArray()
95
- .map((el) => {
96
- const $el = $(el);
97
- const id = $el.attr("id");
98
- const listingId = id?.match(/history_row_(.*?)_/)?.[1];
99
- if (!listingId) return null;
100
- const [gainOrLoss, image, priceText, itemName, gameName, listedOnText, actedOnText, status] = [$el.find(".market_listing_gainorloss").text().trim(), $el.find(".market_listing_item_img").attr("src"), $el.find(".market_table_value .market_listing_price").text(), $el.find(".market_listing_item_name").text().trim(), $el.find(".market_listing_game_name").text().trim(), $el.find(".market_listing_listed_date + .market_listing_listed_date").text(), $el.find(".market_listing_whoactedwith + .market_listing_listed_date").text(), $el.find(".market_listing_whoactedwith").text().trim()];
101
- const price = parseInt(priceText.replace(/[₫().,]/g, "").trim(), 10) || "";
102
- const listedOn = typeof formatMarketHistoryDate === "function" ? formatMarketHistoryDate(listedOnText.replace(/Listed:/, "").trim()) : listedOnText.replace(/Listed:/, "").trim();
103
- const actedOn = typeof formatMarketHistoryDate === "function" ? formatMarketHistoryDate(actedOnText.replace(/Listed:/, "").trim()) : actedOnText.replace(/Listed:/, "").trim();
104
-
105
- const result = {
106
- id,
107
- listingId,
108
- price,
109
- itemName,
110
- gameName,
111
- listedOn,
112
- actedOn,
113
- image,
114
- gainOrLoss,
115
- status,
116
- };
117
- if (assetByListingId?.[listingId]) result.assetId = assetByListingId[listingId];
118
- return result;
119
- })
120
- .filter(Boolean);
121
- }
122
-
123
- /**
124
- * Parses Steam Market HTML listings to an array of items.
125
- *
126
- * @param {string} html - HTML string containing listing rows.
127
- * @returns {Array<{
128
- * listingId: string,
129
- * appId: number,
130
- * contextId: number,
131
- * itemId: number,
132
- * imageUrl: string|null,
133
- * buyerPaysPrice: string,
134
- * receivePrice: string,
135
- * itemName: string,
136
- * gameName: string,
137
- * listedDate: string
138
- * }>}
139
- */
140
- export function parseMarketListings(html) {
141
- const $ = cheerio.load(html);
142
- const results = [];
143
-
144
- $(".market_listing_row").each((index, element) => {
145
- const $row = $(element);
146
-
147
- const cancelLink = $row.find(".market_listing_cancel_button > a").attr("href");
148
- if (!cancelLink) return;
149
-
150
- const paramsMatch = cancelLink.match(/\(([^)]*)\)/);
151
- if (!paramsMatch) return;
152
-
153
- let [, listingId, appId, contextId, itemId] = paramsMatch[1].split(",").map((param) => param.trim().replace(/^['"]|['"]$/g, ""));
154
-
155
- appId = Number(appId);
156
- contextId = Number(contextId);
157
- itemId = Number(itemId);
158
-
159
- const imageUrl = $row.find(`#mylisting_${listingId}_image`).attr("src") || null;
160
-
161
- const buyerPaysElem = $row.find('.market_listing_price span[title="This is the price the buyer pays."]');
162
- const buyerPaysPrice = StringUtils.cleanSpace(buyerPaysElem.text().replace(/[()]/g, ""));
163
-
164
- const receiveElem = $row.find('.market_listing_price span[title="This is how much you will receive."]');
165
- const receivePrice = StringUtils.cleanSpace(receiveElem.text().replace(/[()]/g, ""));
166
-
167
- const itemName = $row.find(".market_listing_item_name_link").text() || $row.find(".market_listing_item_name").text();
168
-
169
- const gameName = $row.find(".market_listing_game_name").text();
170
-
171
- const listedDateElem = $row.find(".market_listing_game_name + .market_listing_listed_date_combined");
172
- const listedDate = formatMarketHistoryDate(StringUtils.cleanSpace(listedDateElem.text()));
173
-
174
- results.push({
175
- listingId,
176
- appId,
177
- contextId,
178
- itemId,
179
- imageUrl,
180
- buyerPaysPrice,
181
- receivePrice,
182
- itemName,
183
- gameName,
184
- listedDate,
185
- });
186
- });
187
-
188
- return results;
189
- }
1
+ import { StringUtils } from "alpha-common-utils/index.js";
2
+ import { formatMarketHistoryDate } from "./utils.js";
3
+ import * as cheerio from "cheerio";
4
+
5
+ /**
6
+ * @typedef {Object} HoverItem
7
+ * @property {string|null} listingId The listing ID extracted from the selector, if available (as string).
8
+ * @property {number} appid The app (game) ID for this item.
9
+ * @property {number} contextid The context ID for this item.
10
+ * @property {number} assetid The unique asset ID.
11
+ * @property {string} unknown A string field captured from the arguments (usually "0").
12
+ * @property {string} [name_selector] The HTML selector for the item's name, if present.
13
+ * @property {string} [image_selector] The HTML selector for the item's image, if present.
14
+ * @property {string} [other_selector] The selector string if it does not match name/image pattern.
15
+ */
16
+
17
+ /**
18
+ * Extracts item information from Steam inventory trade history or similar HTML fragments.
19
+ * Scans the given HTML string for calls to `CreateItemHoverFromContainer` and extracts
20
+ * key data for each referenced item. Returns each item's info in a structured array.
21
+ *
22
+ * @param {string} html - The HTML string to parse.
23
+ * @returns {HoverItem[]} Array of hover item objects.
24
+ */
25
+ export function extractAssetItemsFromHovers(html) {
26
+ // Use your preferred HTML/space scrubber.
27
+ html = StringUtils.cleanSpace(html);
28
+
29
+ // RegExp for CreateItemHoverFromContainer arguments
30
+ const re = /CreateItemHoverFromContainer\s*\(\s*g_rgAssets\s*,\s*'([^']+)'\s*,\s*(\d+)\s*,\s*'(\d+)'\s*,\s*'(\d+)'\s*,\s*(\d+)\s*\)/g;
31
+
32
+ /** @type {Record<number, HoverItem>} */
33
+ const itemsMap = {};
34
+ let match;
35
+
36
+ while ((match = re.exec(html)) !== null) {
37
+ const [_, selector, appid, contextid, assetid, unknown] = match;
38
+
39
+ // Extract listingId as a string if present: "history_row_<listingId>_"
40
+ let listingId = null;
41
+ const lidMatch = selector.match(/history_row_(\d+)_/);
42
+ if (lidMatch) listingId = lidMatch[1]; // assign as string
43
+
44
+ const appidNum = Number(appid);
45
+ const contextidNum = Number(contextid);
46
+ const assetidNum = Number(assetid);
47
+
48
+ if (!itemsMap[assetidNum]) {
49
+ itemsMap[assetidNum] = {
50
+ listingId,
51
+ appid: appidNum,
52
+ contextid: contextidNum,
53
+ assetid: assetidNum,
54
+ unknown,
55
+ };
56
+ }
57
+
58
+ if (selector.endsWith("_name")) {
59
+ itemsMap[assetidNum].name_selector = selector;
60
+ } else if (selector.endsWith("_image")) {
61
+ itemsMap[assetidNum].image_selector = selector;
62
+ } else {
63
+ itemsMap[assetidNum].other_selector = selector;
64
+ }
65
+ }
66
+ return Object.values(itemsMap);
67
+ }
68
+
69
+ /**
70
+ * @typedef {Object} MarketHistoryListing
71
+ * @property {string} id - HTML row id attribute (e.g. "history_row_4316182845737233773_4316182845737233774").
72
+ * @property {string} listingId - Listing id (e.g. "4316182845737233773").
73
+ * @property {number} price - Price in integer form (e.g. 80270).
74
+ * @property {string} itemName - The market item's name (e.g. "UMP-45 | Mudder").
75
+ * @property {string} gameName - The game's name (e.g. "Counter-Strike 2").
76
+ * @property {string} listedOn - Listing date as string (e.g. "27 May 2024").
77
+ * @property {string} actedOn - Acted on date or empty string.
78
+ * @property {string} image - Full image URL for the item.
79
+ * @property {string} gainOrLoss - "+" for buys, "-" for sells.
80
+ * @property {string} status - Status text, usually empty string.
81
+ * @property {string} [assetId] - (optional) Associated asset id, if available.
82
+ */
83
+
84
+ /**
85
+ * Parses Steam market history listing rows into structured data objects.
86
+ *
87
+ * @param {string} html - The raw HTML string to parse.
88
+ * @param {Object} [assetByListingId={}] - Optional mapping of listingId to assetId.
89
+ * @returns {MarketHistoryListing[]} Array of market listing objects.
90
+ */
91
+ export function parseMarketHistoryListings(html, assetByListingId = {}) {
92
+ const $ = cheerio.load(html);
93
+ return $(".market_listing_row")
94
+ .toArray()
95
+ .map((el) => {
96
+ const $el = $(el);
97
+ const id = $el.attr("id");
98
+ const listingId = id?.match(/history_row_(.*?)_/)?.[1];
99
+ if (!listingId) return null;
100
+ const [gainOrLoss, image, priceText, itemName, gameName, listedOnText, actedOnText, status] = [$el.find(".market_listing_gainorloss").text().trim(), $el.find(".market_listing_item_img").attr("src"), $el.find(".market_table_value .market_listing_price").text(), $el.find(".market_listing_item_name").text().trim(), $el.find(".market_listing_game_name").text().trim(), $el.find(".market_listing_listed_date + .market_listing_listed_date").text(), $el.find(".market_listing_whoactedwith + .market_listing_listed_date").text(), $el.find(".market_listing_whoactedwith").text().trim()];
101
+ const price = parseInt(priceText.replace(/[₫().,]/g, "").trim(), 10) || "";
102
+ const listedOn = typeof formatMarketHistoryDate === "function" ? formatMarketHistoryDate(listedOnText.replace(/Listed:/, "").trim()) : listedOnText.replace(/Listed:/, "").trim();
103
+ const actedOn = typeof formatMarketHistoryDate === "function" ? formatMarketHistoryDate(actedOnText.replace(/Listed:/, "").trim()) : actedOnText.replace(/Listed:/, "").trim();
104
+
105
+ const result = {
106
+ id,
107
+ listingId,
108
+ price,
109
+ itemName,
110
+ gameName,
111
+ listedOn,
112
+ actedOn,
113
+ image,
114
+ gainOrLoss,
115
+ status,
116
+ };
117
+ if (assetByListingId?.[listingId]) result.assetId = assetByListingId[listingId];
118
+ return result;
119
+ })
120
+ .filter(Boolean);
121
+ }
122
+
123
+ /**
124
+ * Parses Steam Market HTML listings to an array of items.
125
+ *
126
+ * @param {string} html - HTML string containing listing rows.
127
+ * @returns {Array<{
128
+ * listingId: string,
129
+ * appId: number,
130
+ * contextId: number,
131
+ * itemId: number,
132
+ * imageUrl: string|null,
133
+ * buyerPaysPrice: string,
134
+ * receivePrice: string,
135
+ * itemName: string,
136
+ * gameName: string,
137
+ * listedDate: string
138
+ * }>}
139
+ */
140
+ export function parseMarketListings(html) {
141
+ const $ = cheerio.load(html);
142
+ const results = [];
143
+
144
+ $(".market_listing_row").each((index, element) => {
145
+ const $row = $(element);
146
+
147
+ const cancelLink = $row.find(".market_listing_cancel_button > a").attr("href");
148
+ if (!cancelLink) return;
149
+
150
+ const paramsMatch = cancelLink.match(/\(([^)]*)\)/);
151
+ if (!paramsMatch) return;
152
+
153
+ let [, listingId, appId, contextId, itemId] = paramsMatch[1].split(",").map((param) => param.trim().replace(/^['"]|['"]$/g, ""));
154
+
155
+ appId = Number(appId);
156
+ contextId = Number(contextId);
157
+ itemId = Number(itemId);
158
+
159
+ const imageUrl = $row.find(`#mylisting_${listingId}_image`).attr("src") || null;
160
+
161
+ const buyerPaysElem = $row.find('.market_listing_price span[title="This is the price the buyer pays."]');
162
+ const buyerPaysPrice = StringUtils.cleanSpace(buyerPaysElem.text().replace(/[()]/g, ""));
163
+
164
+ const receiveElem = $row.find('.market_listing_price span[title="This is how much you will receive."]');
165
+ const receivePrice = StringUtils.cleanSpace(receiveElem.text().replace(/[()]/g, ""));
166
+
167
+ const itemName = $row.find(".market_listing_item_name_link").text() || $row.find(".market_listing_item_name").text();
168
+
169
+ const gameName = $row.find(".market_listing_game_name").text();
170
+
171
+ const listedDateElem = $row.find(".market_listing_game_name + .market_listing_listed_date_combined");
172
+ const listedDate = formatMarketHistoryDate(StringUtils.cleanSpace(listedDateElem.text()));
173
+
174
+ results.push({
175
+ listingId,
176
+ appId,
177
+ contextId,
178
+ itemId,
179
+ imageUrl,
180
+ buyerPaysPrice,
181
+ receivePrice,
182
+ itemName,
183
+ gameName,
184
+ listedDate,
185
+ });
186
+ });
187
+
188
+ return results;
189
+ }