From 6f97370710f9795206b3356b85ef6fad604fd4f4 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Fri, 12 May 2023 22:05:20 +0200 Subject: [PATCH 01/22] Add sharedfile comment support --- components/sharedfiles.js | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 components/sharedfiles.js diff --git a/components/sharedfiles.js b/components/sharedfiles.js new file mode 100644 index 0000000..eda5ea8 --- /dev/null +++ b/components/sharedfiles.js @@ -0,0 +1,60 @@ +var SteamCommunity = require('../index.js'); +var SteamID = require('steamid'); + +// Note: a CSteamSharedfile class does not exist because we can't get data using the "normal" xml way to fill a CSteamSharedfile object + +/** + * Deletes a comment from a sharedfile's comment section + * @param {SteamID | String} userID - ID of the user associated to this sharedfile + * @param {String} sid - ID of the sharedfile + * @param {String} cid - ID of the comment to delete + * @param {function} callback - Takes only an Error object/null as the first argument + */ +SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, callback) { + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/delete/${userID.toString()}/${sid}/`, + "form": { + "gidcomment": cid, + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; + +/** + * Posts a comment to a sharedfile + * @param {SteamID | String} userID - ID of the user associated to this sharedfile + * @param {String} sid - ID of the sharedfile + * @param {String} message - Content of the comment to post + * @param {function} callback - Takes only an Error object/null as the first argument + */ +SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, callback) { + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/post/${userID.toString()}/${sid}/`, + "form": { + "comment": message, + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; \ No newline at end of file From 18011b3fac901969642a48b9012cadab3df449f6 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Fri, 12 May 2023 22:10:37 +0200 Subject: [PATCH 02/22] Add sharedfile voting support --- components/sharedfiles.js | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/components/sharedfiles.js b/components/sharedfiles.js index eda5ea8..cb8f116 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -55,6 +55,48 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, return; } + callback(null || err); + }, "steamcommunity"); +}; + +/** + * Downvotes a sharedfile + * @param {String} sid - ID of the sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +SteamCommunity.prototype.voteDownSharedfile = function(sid, callback) { + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/votedown", + "form": { + "id": sid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; + +/** + * Upvotes a sharedfile + * @param {String} sid - ID of the sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +SteamCommunity.prototype.voteUpSharedfile = function(sid, callback) { + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/voteup", + "form": { + "id": sid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + callback(null || err); }, "steamcommunity"); }; \ No newline at end of file From d807f106532811294cc360ed288f58014c55ba27 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Fri, 12 May 2023 23:16:01 +0200 Subject: [PATCH 03/22] Add sharedfile subscribing support --- components/sharedfiles.js | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/components/sharedfiles.js b/components/sharedfiles.js index cb8f116..0d0a6b9 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -59,6 +59,58 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, }, "steamcommunity"); }; +/** + * Subscribes to a sharedfile's comment section. Note: Checkbox on webpage does not update + * @param {SteamID | String} userID ID of the user associated to this sharedfile + * @param {String} sid ID of the sharedfileof + * @param {function} callback - Takes only an Error object/null as the first argument + */ +Bot.prototype.subscribeSharedfileComments = function(userID, sid, callback) { + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/subscribe/${userID.toString()}/${sid}/`, + "form": { + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { // eslint-disable-line + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; + +/** + * Unsubscribes from a sharedfile's comment section. Note: Checkbox on webpage does not update + * @param {SteamID | String} userID - ID of the user associated to this sharedfile + * @param {String} sid - ID of the sharedfileof + * @param {function} callback - Takes only an Error object/null as the first argument + */ +Bot.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/unsubscribe/${userID.toString()}/${sid}/`, + "form": { + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { // eslint-disable-line + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; + /** * Downvotes a sharedfile * @param {String} sid - ID of the sharedfile From f09adc84a400f538c0a7967cbf416c40328c5ff0 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Fri, 12 May 2023 23:30:10 +0200 Subject: [PATCH 04/22] Add (disabled) sharedfile favorite support --- components/sharedfiles.js | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 0d0a6b9..13ac48a 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -31,6 +31,28 @@ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, ca }, "steamcommunity"); }; +/** + * Favorites a sharedfile + * @param {String} sid - ID of the sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +/* SteamCommunity.prototype.favoriteSharedfile = function(sid, callback) { + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/favorite", + "form": { + "id": sid, + "appid": , // TODO: How to get appid the sharedfile is associated to? + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; */ + /** * Posts a comment to a sharedfile * @param {SteamID | String} userID - ID of the user associated to this sharedfile @@ -85,6 +107,28 @@ Bot.prototype.subscribeSharedfileComments = function(userID, sid, callback) { }, "steamcommunity"); }; +/** + * Unfavorites a sharedfile + * @param {String} sid - ID of the sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +/* SteamCommunity.prototype.unfavoriteSharedfile = function(sid, callback) { + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/unfavorite", + "form": { + "id": sid, + "appid": , // TODO: How to get appid the sharedfile is associated to? + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); +}; */ + /** * Unsubscribes from a sharedfile's comment section. Note: Checkbox on webpage does not update * @param {SteamID | String} userID - ID of the user associated to this sharedfile From b55516f67f953e3306903e705dac050004bae1a7 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Fri, 12 May 2023 23:46:31 +0200 Subject: [PATCH 05/22] Oops, wrong object name --- components/sharedfiles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 13ac48a..8670421 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -87,7 +87,7 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, * @param {String} sid ID of the sharedfileof * @param {function} callback - Takes only an Error object/null as the first argument */ -Bot.prototype.subscribeSharedfileComments = function(userID, sid, callback) { +SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } @@ -135,7 +135,7 @@ Bot.prototype.subscribeSharedfileComments = function(userID, sid, callback) { * @param {String} sid - ID of the sharedfileof * @param {function} callback - Takes only an Error object/null as the first argument */ -Bot.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { +SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } From c92801d25ee8c23f3956c0fc3d2b2ed6be5a17b4 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sat, 13 May 2023 16:09:47 +0200 Subject: [PATCH 06/22] Load sharedfiles component --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 54d028d..10c58ba 100644 --- a/index.js +++ b/index.js @@ -573,6 +573,7 @@ require('./components/profile.js'); require('./components/market.js'); require('./components/groups.js'); require('./components/users.js'); +require("./components/sharedfiles.js"); require('./components/inventoryhistory.js'); require('./components/webapi.js'); require('./components/twofactor.js'); From c8642865a133a0b2e156d029655eaba3e9fde2b6 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 14:50:32 +0200 Subject: [PATCH 07/22] Add sharedfile type enum --- resources/ESharedfileType.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 resources/ESharedfileType.js diff --git a/resources/ESharedfileType.js b/resources/ESharedfileType.js new file mode 100644 index 0000000..b8732ce --- /dev/null +++ b/resources/ESharedfileType.js @@ -0,0 +1,13 @@ +/** + * @enum ESharedfileType + */ +module.exports = { + "Screenshot": 0, + "Artwork": 1, + "Guide": 2, + + // Value-to-name mapping for convenience + "0": "Screenshot", + "1": "Artwork", + "2": "Guide" +}; \ No newline at end of file From 9ec5dcd7b0f8c44cce6ca2193bc93adbc571bac8 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 15:00:45 +0200 Subject: [PATCH 08/22] Add sharedfile class with fully working scraper --- classes/CSteamSharedfile.js | 152 ++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 153 insertions(+) create mode 100644 classes/CSteamSharedfile.js diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js new file mode 100644 index 0000000..072996a --- /dev/null +++ b/classes/CSteamSharedfile.js @@ -0,0 +1,152 @@ +const Cheerio = require("cheerio"); +const SteamID = require("steamid"); +const SteamCommunity = require("../index.js"); +const steamIdResolver = require("steamid-resolver"); +const ESharedfileType = require("../resources/ESharedfileType.js"); + + +/** + * Scrape a sharedfile's DOM to get all available information + * @param {String} sid - ID of the sharedfile + * @param {function} callback - First argument is null/Error, second is object containing all available information + */ +SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { + // Construct object holding all the data we can scrape + let sharedfile = { + id: sid, + type: null, + appID: null, + owner: null, + fileSize: null, + postDate: null, + resolution: null, + uniqueVisitorsCount: null, + favoritesCount: null, + upvoteCount: null + } + + + // Get DOM of sharedfile + this.httpRequestGet(`https://steamcommunity.com/sharedfiles/filedetails/?id=${sid}`, (err, res, body) => { + try { + + /* --------------------- Preprocess output --------------------- */ + + // Load output into cheerio to make parsing easier + let $ = Cheerio.load(body); + + // Dynamically map detailsStatsContainerLeft to detailsStatsContainerRight in an object to make readout easier. It holds size, post date and resolution. + let detailsStatsObj = {}; + let detailsLeft = $(".detailsStatsContainerLeft").children(); + let detailsRight = $(".detailsStatsContainerRight").children(); + + Object.keys(detailsLeft).forEach((e) => { // Dynamically get all details. Don't hardcore so that this also works for guides. + if (isNaN(e)) return; // Ignore invalid entries + + detailsStatsObj[detailsLeft[e].children[0].data.trim()] = detailsRight[e].children[0].data; + }); + + // Dynamically map stats_table descriptions to values. This holds Unique Visitors and Current Favorites + let statsTableObj = {}; + let statsTable = $(".stats_table").children(); + + Object.keys(statsTable).forEach((e, i) => { + if (isNaN(e)) return; // Ignore invalid entries + + // Value description is at index 3, value data at index 1 + statsTableObj[statsTable[e].children[3].children[0].data] = statsTable[e].children[1].children[0].data.replace(/,/g, ""); // Remove commas from 1k+ values + }); + + + /* --------------------- Find and map values --------------------- */ + + // Find appID in share button onclick event + sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sid}', '`, "").replace("' );", "")) + + + // Find owner profile link, convert to steamID64 using steamIdResolver lib and create a SteamID object + let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; + + steamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // Note: Callback will be called before this is done, takes around 1 sec to populate + if (!err) sharedfile.owner = new SteamID(steamID64); + }); + + + // Find fileSize if not guide + sharedfile.fileSize = detailsStatsObj["File Size"] || null; // TODO: Convert to bytes? It seems like to always be MB but no guarantee + + // Find postDate and convert to timestamp (Warning: Will get ugly) + let posted = detailsStatsObj["Posted"].replace(/,|@/g, "").split(" "); // Remove comma behind month and @, the date & time separator. Split by space to get: Day, Month, Year (if not current) and time + let months = { "Jan": "01", "Feb": "02", "Mar": "03", "Apr": "04", "May": "05", "Jun": "06", "Jul": "07", "Aug": "08", "Sep": "09", "Oct": "10", "Nov": "11", "Dec": "12" }; // Map all month abbreviations + + if (posted[0].split(":")[0].length == 1) posted[0] = "0" + posted[0]; // Add zero if day is <10 to have a fixed length + + posted[1] = months[posted[1]]; // Replace month abbreviation with corresponding Number + + if (!posted[2]) posted[2] = new Date().getUTCFullYear().toString(); // Add current year if Steam did not list one + else posted.splice(3, 1); // ...otherwise remove element 3 as it will be an empty String + + // Convert AM/PM time to 24h format - Credit: https://stackoverflow.com/a/40197728 (Modified) + if (posted[3].split(":")[0].length == 1) posted[3] = "0" + posted[3]; // Add zero if hour is <10 to have a fixed length + + let time = posted[3].substring(0, 5); + let modifier = posted[3].substring(5, 7); + let [hours, minutes] = time.split(":"); + + if (hours === "12") hours = "00"; + if (modifier === "pm") hours = parseInt(hours, 10) + 12; + + sharedfile.postDate = Date.parse(`${posted[2]}-${posted[1]}-${posted[0]}T${hours}:${minutes}:00.000Z`); // Construct Date String and parse it to get Unix timestamp + + + // Find resolution if artwork or screenshot + sharedfile.resolution = detailsStatsObj["Size"] || null; + + + // Find uniqueVisitorsCount. We can't use ' || null' here as Number("0") casts to false + if (statsTableObj["Unique Visitors"]) sharedfile.uniqueVisitorsCount = Number(statsTableObj["Unique Visitors"]); + + + // Find favoritesCount. We can't use ' || null' here as Number("0") casts to false + if (statsTableObj["Current Favorites"]) sharedfile.favoritesCount = Number(statsTableObj["Current Favorites"]); + + + // Find upvoteCount. We can't use ' || null' here as Number("0") casts to false + let upvoteCount = $("#VotesUpCountContainer > #VotesUpCount").text(); + if (upvoteCount) sharedfile.upvoteCount = Number(upvoteCount); + + + // Determine type by looking at the second breadcrumb. Find the first separator as it has a unique name and go to the next element which holds our value of interest + let breadcrumb = $(".breadcrumbs > .breadcrumb_separator").next().get(0).children[0].data || ""; + + if (breadcrumb.includes("Screenshot")) sharedfile.type = ESharedfileType.Screenshot; + if (breadcrumb.includes("Artwork")) sharedfile.type = ESharedfileType.Artwork; + if (breadcrumb.includes("Guide")) sharedfile.type = ESharedfileType.Guide; + + + callback(null, new CSteamSharedfile(this, sharedfile)); + + } catch (err) { + callback(err, null); + } + }); +} + + +function CSteamSharedfile(community, data) { + this._community = community; + + // Clone all the data we recieved + Object.assign(this, data); // TODO: This is cleaner but might break IntelliSense + + /* this.id = data.id; + this.type = data.type; + this.appID = data.appID; + this.owner = data.owner; + this.fileSize = data.fileSize; + this.postDate = data.postDate; + this.resolution = data.resolution; + this.uniqueVisitorsCount = data.uniqueVisitorsCount; + this.favoritesCount = data.favoritesCount; + this.upvoteCount = data.upvoteCount; */ +} \ No newline at end of file diff --git a/package.json b/package.json index afd186a..64709eb 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "request": "^2.88.0", "steam-totp": "^1.5.0", "steamid": "^1.1.3", + "steamid-resolver": "^1.2.3", "xml2js": "^0.4.22" }, "engines": { From d6b0fbd5d0a7914d5e88b4bb496c302546a017c8 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 15:07:23 +0200 Subject: [PATCH 09/22] Update non-object methods to take appid param --- components/sharedfiles.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 8670421..08f5c52 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -34,14 +34,15 @@ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, ca /** * Favorites a sharedfile * @param {String} sid - ID of the sharedfile + * @param {String} appid - ID of the app associated to this sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -/* SteamCommunity.prototype.favoriteSharedfile = function(sid, callback) { +SteamCommunity.prototype.favoriteSharedfile = function(sid, appid, callback) { this.httpRequestPost({ "uri": "https://steamcommunity.com/sharedfiles/favorite", "form": { "id": sid, - "appid": , // TODO: How to get appid the sharedfile is associated to? + "appid": appid, "sessionid": this.getSessionID() } }, function(err, response, body) { @@ -51,7 +52,7 @@ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, ca callback(null || err); }, "steamcommunity"); -}; */ +}; /** * Posts a comment to a sharedfile @@ -110,14 +111,15 @@ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, cal /** * Unfavorites a sharedfile * @param {String} sid - ID of the sharedfile + * @param {String} appid - ID of the app associated to this sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -/* SteamCommunity.prototype.unfavoriteSharedfile = function(sid, callback) { +SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { this.httpRequestPost({ "uri": "https://steamcommunity.com/sharedfiles/unfavorite", "form": { "id": sid, - "appid": , // TODO: How to get appid the sharedfile is associated to? + "appid": appid, "sessionid": this.getSessionID() } }, function(err, response, body) { @@ -127,7 +129,7 @@ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, cal callback(null || err); }, "steamcommunity"); -}; */ +}; /** * Unsubscribes from a sharedfile's comment section. Note: Checkbox on webpage does not update From ba2782066d4a0b588b3a9c548585f2b2a79c16d5 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 15:22:15 +0200 Subject: [PATCH 10/22] Misc --- classes/CSteamSharedfile.js | 5 ++--- components/sharedfiles.js | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 072996a..0094807 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -129,9 +129,8 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { } catch (err) { callback(err, null); } - }); -} - + }, "steamcommunity"); +}; function CSteamSharedfile(community, data) { this._community = community; diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 08f5c52..be9fe3a 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -1,7 +1,6 @@ var SteamCommunity = require('../index.js'); var SteamID = require('steamid'); -// Note: a CSteamSharedfile class does not exist because we can't get data using the "normal" xml way to fill a CSteamSharedfile object /** * Deletes a comment from a sharedfile's comment section @@ -85,7 +84,7 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, /** * Subscribes to a sharedfile's comment section. Note: Checkbox on webpage does not update * @param {SteamID | String} userID ID of the user associated to this sharedfile - * @param {String} sid ID of the sharedfileof + * @param {String} sid ID of the sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, callback) { @@ -134,7 +133,7 @@ SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { /** * Unsubscribes from a sharedfile's comment section. Note: Checkbox on webpage does not update * @param {SteamID | String} userID - ID of the user associated to this sharedfile - * @param {String} sid - ID of the sharedfileof + * @param {String} sid - ID of the sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { From 350f6288e4f9796d6d123a1cf2c3d4ca10315e4e Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 15:26:55 +0200 Subject: [PATCH 11/22] Add sharedfile object methods --- classes/CSteamSharedfile.js | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 0094807..40ccdfe 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -148,4 +148,70 @@ function CSteamSharedfile(community, data) { this.uniqueVisitorsCount = data.uniqueVisitorsCount; this.favoritesCount = data.favoritesCount; this.upvoteCount = data.upvoteCount; */ -} \ No newline at end of file +} + +/** + * Deletes a comment from this sharedfile's comment section + * @param {String} cid - ID of the comment to delete + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.deleteComment = function(cid, callback) { + this._community.deleteSharedfileComment(this.userID, this.sid, cid, callback); +}; + +/** + * Favorites this sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.favorite = function(callback) { + this._community.favoriteSharedfile(this.sid, this.appID, callback); +}; + +/** + * Posts a comment to this sharedfile + * @param {String} message - Content of the comment to post + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.comment = function(message, callback) { + this._community.postSharedfileComment(this.owner, this.sid, message, callback); +}; + +/** + * Subscribes to this sharedfile's comment section. Note: Checkbox on webpage does not update + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.subscribe = function(callback) { + this._community.subscribeSharedfileComments(this.owner, this.sid, callback); +}; + +/** + * Unfavorites this sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.unfavorite = function(callback) { + this._community.unfavoriteSharedfile(this.sid, this.appID, callback); +}; + +/** + * Unsubscribes from this sharedfile's comment section. Note: Checkbox on webpage does not update + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.unsubscribe = function(callback) { + this._community.unsubscribeSharedfileComments(this.owner, this.sid, callback); +}; + +/** + * Downvotes this sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.voteDown = function(callback) { + this._community.voteDownSharedfile(this.sid, callback); +}; + +/** + * Upvotes this sharedfile + * @param {function} callback - Takes only an Error object/null as the first argument + */ +CSteamSharedfile.prototype.voteUp = function(callback) { + this._community.voteUpSharedfile(this.sid, callback); +}; \ No newline at end of file From c0be17cd612817a628f999de5a59a424c6bf3037 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 15:47:49 +0200 Subject: [PATCH 12/22] Load CSteamSharedfile class --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 10c58ba..64e3756 100644 --- a/index.js +++ b/index.js @@ -573,7 +573,7 @@ require('./components/profile.js'); require('./components/market.js'); require('./components/groups.js'); require('./components/users.js'); -require("./components/sharedfiles.js"); +require('./components/sharedfiles.js'); require('./components/inventoryhistory.js'); require('./components/webapi.js'); require('./components/twofactor.js'); @@ -582,6 +582,7 @@ require('./components/help.js'); require('./classes/CMarketItem.js'); require('./classes/CMarketSearchResult.js'); require('./classes/CSteamGroup.js'); +require('./classes/CSteamSharedfile.js'); require('./classes/CSteamUser.js'); /** From 8538589fef6d3a7da7d2e1074e08beab28b0bc47 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 16:12:59 +0200 Subject: [PATCH 13/22] Fix owner remaining null and wrong param --- classes/CSteamSharedfile.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 40ccdfe..04ba9c0 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -64,14 +64,6 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sid}', '`, "").replace("' );", "")) - // Find owner profile link, convert to steamID64 using steamIdResolver lib and create a SteamID object - let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; - - steamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // Note: Callback will be called before this is done, takes around 1 sec to populate - if (!err) sharedfile.owner = new SteamID(steamID64); - }); - - // Find fileSize if not guide sharedfile.fileSize = detailsStatsObj["File Size"] || null; // TODO: Convert to bytes? It seems like to always be MB but no guarantee @@ -124,7 +116,15 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { if (breadcrumb.includes("Guide")) sharedfile.type = ESharedfileType.Guide; - callback(null, new CSteamSharedfile(this, sharedfile)); + // Find owner profile link, convert to steamID64 using steamIdResolver lib and create a SteamID object + let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; + + steamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec + if (!err) sharedfile.owner = new SteamID(steamID64); + + // Make callback when ID was resolved as otherwise owner will always be null + callback(null, new CSteamSharedfile(this, sharedfile)); + }); } catch (err) { callback(err, null); @@ -156,7 +156,7 @@ function CSteamSharedfile(community, data) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.deleteComment = function(cid, callback) { - this._community.deleteSharedfileComment(this.userID, this.sid, cid, callback); + this._community.deleteSharedfileComment(this.userID, this.id, cid, callback); }; /** @@ -164,7 +164,7 @@ CSteamSharedfile.prototype.deleteComment = function(cid, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.favorite = function(callback) { - this._community.favoriteSharedfile(this.sid, this.appID, callback); + this._community.favoriteSharedfile(this.id, this.appID, callback); }; /** @@ -173,7 +173,7 @@ CSteamSharedfile.prototype.favorite = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.comment = function(message, callback) { - this._community.postSharedfileComment(this.owner, this.sid, message, callback); + this._community.postSharedfileComment(this.owner, this.id, message, callback); }; /** @@ -181,7 +181,7 @@ CSteamSharedfile.prototype.comment = function(message, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.subscribe = function(callback) { - this._community.subscribeSharedfileComments(this.owner, this.sid, callback); + this._community.subscribeSharedfileComments(this.owner, this.id, callback); }; /** @@ -189,7 +189,7 @@ CSteamSharedfile.prototype.subscribe = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.unfavorite = function(callback) { - this._community.unfavoriteSharedfile(this.sid, this.appID, callback); + this._community.unfavoriteSharedfile(this.id, this.appID, callback); }; /** @@ -197,7 +197,7 @@ CSteamSharedfile.prototype.unfavorite = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.unsubscribe = function(callback) { - this._community.unsubscribeSharedfileComments(this.owner, this.sid, callback); + this._community.unsubscribeSharedfileComments(this.owner, this.id, callback); }; /** @@ -205,7 +205,7 @@ CSteamSharedfile.prototype.unsubscribe = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.voteDown = function(callback) { - this._community.voteDownSharedfile(this.sid, callback); + this._community.voteDownSharedfile(this.id, callback); }; /** @@ -213,5 +213,5 @@ CSteamSharedfile.prototype.voteDown = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.voteUp = function(callback) { - this._community.voteUpSharedfile(this.sid, callback); + this._community.voteUpSharedfile(this.id, callback); }; \ No newline at end of file From 81d8dc2a5cefa0940bbc93cd6eb1bafbeec5a255 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 16:27:09 +0200 Subject: [PATCH 14/22] Use decodeSteamTime() helper instead of doing it manually --- classes/CSteamSharedfile.js | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 04ba9c0..de9db50 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -1,7 +1,8 @@ const Cheerio = require("cheerio"); const SteamID = require("steamid"); +const Helpers = require('../components/helpers.js'); const SteamCommunity = require("../index.js"); -const steamIdResolver = require("steamid-resolver"); +const SteamIdResolver = require("steamid-resolver"); const ESharedfileType = require("../resources/ESharedfileType.js"); @@ -67,28 +68,11 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { // Find fileSize if not guide sharedfile.fileSize = detailsStatsObj["File Size"] || null; // TODO: Convert to bytes? It seems like to always be MB but no guarantee - // Find postDate and convert to timestamp (Warning: Will get ugly) - let posted = detailsStatsObj["Posted"].replace(/,|@/g, "").split(" "); // Remove comma behind month and @, the date & time separator. Split by space to get: Day, Month, Year (if not current) and time - let months = { "Jan": "01", "Feb": "02", "Mar": "03", "Apr": "04", "May": "05", "Jun": "06", "Jul": "07", "Aug": "08", "Sep": "09", "Oct": "10", "Nov": "11", "Dec": "12" }; // Map all month abbreviations - if (posted[0].split(":")[0].length == 1) posted[0] = "0" + posted[0]; // Add zero if day is <10 to have a fixed length + // Find postDate and convert to timestamp + let posted = detailsStatsObj["Posted"].trim(); - posted[1] = months[posted[1]]; // Replace month abbreviation with corresponding Number - - if (!posted[2]) posted[2] = new Date().getUTCFullYear().toString(); // Add current year if Steam did not list one - else posted.splice(3, 1); // ...otherwise remove element 3 as it will be an empty String - - // Convert AM/PM time to 24h format - Credit: https://stackoverflow.com/a/40197728 (Modified) - if (posted[3].split(":")[0].length == 1) posted[3] = "0" + posted[3]; // Add zero if hour is <10 to have a fixed length - - let time = posted[3].substring(0, 5); - let modifier = posted[3].substring(5, 7); - let [hours, minutes] = time.split(":"); - - if (hours === "12") hours = "00"; - if (modifier === "pm") hours = parseInt(hours, 10) + 12; - - sharedfile.postDate = Date.parse(`${posted[2]}-${posted[1]}-${posted[0]}T${hours}:${minutes}:00.000Z`); // Construct Date String and parse it to get Unix timestamp + sharedfile.postDate = Date.parse(Helpers.decodeSteamTime(posted)); // Pass String into helper and parse the returned String to get a Unix timestamp // Find resolution if artwork or screenshot @@ -116,10 +100,10 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { if (breadcrumb.includes("Guide")) sharedfile.type = ESharedfileType.Guide; - // Find owner profile link, convert to steamID64 using steamIdResolver lib and create a SteamID object + // Find owner profile link, convert to steamID64 using SteamIdResolver lib and create a SteamID object let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; - steamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec + SteamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec if (!err) sharedfile.owner = new SteamID(steamID64); // Make callback when ID was resolved as otherwise owner will always be null From 897ad161544f80fb2a4d01a7b8bb34b9b0a41071 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 14 May 2023 18:52:16 +0200 Subject: [PATCH 15/22] Formatting --- classes/CSteamSharedfile.js | 216 ++++++++++++++++-------------- components/sharedfiles.js | 248 +++++++++++++++++------------------ resources/ESharedfileType.js | 14 +- 3 files changed, 250 insertions(+), 228 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index de9db50..8ed43ad 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -1,9 +1,9 @@ -const Cheerio = require("cheerio"); -const SteamID = require("steamid"); +const Cheerio = require('cheerio'); +const SteamID = require('steamid'); const Helpers = require('../components/helpers.js'); -const SteamCommunity = require("../index.js"); -const SteamIdResolver = require("steamid-resolver"); -const ESharedfileType = require("../resources/ESharedfileType.js"); +const SteamCommunity = require('../index.js'); +const SteamIdResolver = require('steamid-resolver'); +const ESharedfileType = require('../resources/ESharedfileType.js'); /** @@ -12,126 +12,148 @@ const ESharedfileType = require("../resources/ESharedfileType.js"); * @param {function} callback - First argument is null/Error, second is object containing all available information */ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { - // Construct object holding all the data we can scrape - let sharedfile = { - id: sid, - type: null, - appID: null, - owner: null, - fileSize: null, - postDate: null, - resolution: null, - uniqueVisitorsCount: null, - favoritesCount: null, - upvoteCount: null - } + // Construct object holding all the data we can scrape + let sharedfile = { + id: sid, + type: null, + appID: null, + owner: null, + fileSize: null, + postDate: null, + resolution: null, + uniqueVisitorsCount: null, + favoritesCount: null, + upvoteCount: null + }; - // Get DOM of sharedfile - this.httpRequestGet(`https://steamcommunity.com/sharedfiles/filedetails/?id=${sid}`, (err, res, body) => { - try { - /* --------------------- Preprocess output --------------------- */ + // Get DOM of sharedfile + this.httpRequestGet(`https://steamcommunity.com/sharedfiles/filedetails/?id=${sid}`, (err, res, body) => { + try { - // Load output into cheerio to make parsing easier - let $ = Cheerio.load(body); + /* --------------------- Preprocess output --------------------- */ - // Dynamically map detailsStatsContainerLeft to detailsStatsContainerRight in an object to make readout easier. It holds size, post date and resolution. - let detailsStatsObj = {}; - let detailsLeft = $(".detailsStatsContainerLeft").children(); - let detailsRight = $(".detailsStatsContainerRight").children(); + // Load output into cheerio to make parsing easier + let $ = Cheerio.load(body); - Object.keys(detailsLeft).forEach((e) => { // Dynamically get all details. Don't hardcore so that this also works for guides. - if (isNaN(e)) return; // Ignore invalid entries + // Dynamically map detailsStatsContainerLeft to detailsStatsContainerRight in an object to make readout easier. It holds size, post date and resolution. + let detailsStatsObj = {}; + let detailsLeft = $(".detailsStatsContainerLeft").children(); + let detailsRight = $(".detailsStatsContainerRight").children(); - detailsStatsObj[detailsLeft[e].children[0].data.trim()] = detailsRight[e].children[0].data; - }); + Object.keys(detailsLeft).forEach((e) => { // Dynamically get all details. Don't hardcore so that this also works for guides. + if (isNaN(e)) { + return; // Ignore invalid entries + } - // Dynamically map stats_table descriptions to values. This holds Unique Visitors and Current Favorites - let statsTableObj = {}; - let statsTable = $(".stats_table").children(); + detailsStatsObj[detailsLeft[e].children[0].data.trim()] = detailsRight[e].children[0].data; + }); - Object.keys(statsTable).forEach((e, i) => { - if (isNaN(e)) return; // Ignore invalid entries + // Dynamically map stats_table descriptions to values. This holds Unique Visitors and Current Favorites + let statsTableObj = {}; + let statsTable = $(".stats_table").children(); - // Value description is at index 3, value data at index 1 - statsTableObj[statsTable[e].children[3].children[0].data] = statsTable[e].children[1].children[0].data.replace(/,/g, ""); // Remove commas from 1k+ values - }); + Object.keys(statsTable).forEach((e) => { + if (isNaN(e)) { + return; // Ignore invalid entries + } + // Value description is at index 3, value data at index 1 + statsTableObj[statsTable[e].children[3].children[0].data] = statsTable[e].children[1].children[0].data.replace(/,/g, ""); // Remove commas from 1k+ values + }); - /* --------------------- Find and map values --------------------- */ - // Find appID in share button onclick event - sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sid}', '`, "").replace("' );", "")) + /* --------------------- Find and map values --------------------- */ + // Find appID in share button onclick event + sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sid}', '`, "").replace("' );", "")); - // Find fileSize if not guide - sharedfile.fileSize = detailsStatsObj["File Size"] || null; // TODO: Convert to bytes? It seems like to always be MB but no guarantee + // Find fileSize if not guide + sharedfile.fileSize = detailsStatsObj["File Size"] || null; // TODO: Convert to bytes? It seems like to always be MB but no guarantee - // Find postDate and convert to timestamp - let posted = detailsStatsObj["Posted"].trim(); - sharedfile.postDate = Date.parse(Helpers.decodeSteamTime(posted)); // Pass String into helper and parse the returned String to get a Unix timestamp + // Find postDate and convert to timestamp + let posted = detailsStatsObj["Posted"].trim(); + sharedfile.postDate = Date.parse(Helpers.decodeSteamTime(posted)); // Pass String into helper and parse the returned String to get a Unix timestamp - // Find resolution if artwork or screenshot - sharedfile.resolution = detailsStatsObj["Size"] || null; + // Find resolution if artwork or screenshot + sharedfile.resolution = detailsStatsObj["Size"] || null; - // Find uniqueVisitorsCount. We can't use ' || null' here as Number("0") casts to false - if (statsTableObj["Unique Visitors"]) sharedfile.uniqueVisitorsCount = Number(statsTableObj["Unique Visitors"]); + // Find uniqueVisitorsCount. We can't use ' || null' here as Number("0") casts to false + if (statsTableObj["Unique Visitors"]) { + sharedfile.uniqueVisitorsCount = Number(statsTableObj["Unique Visitors"]); + } - // Find favoritesCount. We can't use ' || null' here as Number("0") casts to false - if (statsTableObj["Current Favorites"]) sharedfile.favoritesCount = Number(statsTableObj["Current Favorites"]); + // Find favoritesCount. We can't use ' || null' here as Number("0") casts to false + if (statsTableObj["Current Favorites"]) { + sharedfile.favoritesCount = Number(statsTableObj["Current Favorites"]); + } - // Find upvoteCount. We can't use ' || null' here as Number("0") casts to false - let upvoteCount = $("#VotesUpCountContainer > #VotesUpCount").text(); - if (upvoteCount) sharedfile.upvoteCount = Number(upvoteCount); + // Find upvoteCount. We can't use ' || null' here as Number("0") casts to false + let upvoteCount = $("#VotesUpCountContainer > #VotesUpCount").text(); - // Determine type by looking at the second breadcrumb. Find the first separator as it has a unique name and go to the next element which holds our value of interest - let breadcrumb = $(".breadcrumbs > .breadcrumb_separator").next().get(0).children[0].data || ""; - - if (breadcrumb.includes("Screenshot")) sharedfile.type = ESharedfileType.Screenshot; - if (breadcrumb.includes("Artwork")) sharedfile.type = ESharedfileType.Artwork; - if (breadcrumb.includes("Guide")) sharedfile.type = ESharedfileType.Guide; + if (upvoteCount) { + sharedfile.upvoteCount = Number(upvoteCount); + } - // Find owner profile link, convert to steamID64 using SteamIdResolver lib and create a SteamID object - let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; + // Determine type by looking at the second breadcrumb. Find the first separator as it has a unique name and go to the next element which holds our value of interest + let breadcrumb = $(".breadcrumbs > .breadcrumb_separator").next().get(0).children[0].data || ""; - SteamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec - if (!err) sharedfile.owner = new SteamID(steamID64); + if (breadcrumb.includes("Screenshot")) { + sharedfile.type = ESharedfileType.Screenshot; + } - // Make callback when ID was resolved as otherwise owner will always be null - callback(null, new CSteamSharedfile(this, sharedfile)); - }); + if (breadcrumb.includes("Artwork")) { + sharedfile.type = ESharedfileType.Artwork; + } - } catch (err) { - callback(err, null); - } - }, "steamcommunity"); + if (breadcrumb.includes("Guide")) { + sharedfile.type = ESharedfileType.Guide; + } + + + // Find owner profile link, convert to steamID64 using SteamIdResolver lib and create a SteamID object + let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; + + SteamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec + if (!err) { + sharedfile.owner = new SteamID(steamID64); + } + + // Make callback when ID was resolved as otherwise owner will always be null + callback(null, new CSteamSharedfile(this, sharedfile)); + }); + + } catch (err) { + callback(err, null); + } + }, "steamcommunity"); }; function CSteamSharedfile(community, data) { - this._community = community; - - // Clone all the data we recieved - Object.assign(this, data); // TODO: This is cleaner but might break IntelliSense - - /* this.id = data.id; - this.type = data.type; - this.appID = data.appID; - this.owner = data.owner; - this.fileSize = data.fileSize; - this.postDate = data.postDate; - this.resolution = data.resolution; - this.uniqueVisitorsCount = data.uniqueVisitorsCount; - this.favoritesCount = data.favoritesCount; - this.upvoteCount = data.upvoteCount; */ + this._community = community; + + // Clone all the data we recieved + Object.assign(this, data); // TODO: This is cleaner but might break IntelliSense. I'm leaving the block below to be reactivated if necessary + + /* this.id = data.id; + this.type = data.type; + this.appID = data.appID; + this.owner = data.owner; + this.fileSize = data.fileSize; + this.postDate = data.postDate; + this.resolution = data.resolution; + this.uniqueVisitorsCount = data.uniqueVisitorsCount; + this.favoritesCount = data.favoritesCount; + this.upvoteCount = data.upvoteCount; */ } /** @@ -140,7 +162,7 @@ function CSteamSharedfile(community, data) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.deleteComment = function(cid, callback) { - this._community.deleteSharedfileComment(this.userID, this.id, cid, callback); + this._community.deleteSharedfileComment(this.userID, this.id, cid, callback); }; /** @@ -148,7 +170,7 @@ CSteamSharedfile.prototype.deleteComment = function(cid, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.favorite = function(callback) { - this._community.favoriteSharedfile(this.id, this.appID, callback); + this._community.favoriteSharedfile(this.id, this.appID, callback); }; /** @@ -157,7 +179,7 @@ CSteamSharedfile.prototype.favorite = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.comment = function(message, callback) { - this._community.postSharedfileComment(this.owner, this.id, message, callback); + this._community.postSharedfileComment(this.owner, this.id, message, callback); }; /** @@ -165,7 +187,7 @@ CSteamSharedfile.prototype.comment = function(message, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.subscribe = function(callback) { - this._community.subscribeSharedfileComments(this.owner, this.id, callback); + this._community.subscribeSharedfileComments(this.owner, this.id, callback); }; /** @@ -173,7 +195,7 @@ CSteamSharedfile.prototype.subscribe = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.unfavorite = function(callback) { - this._community.unfavoriteSharedfile(this.id, this.appID, callback); + this._community.unfavoriteSharedfile(this.id, this.appID, callback); }; /** @@ -181,7 +203,7 @@ CSteamSharedfile.prototype.unfavorite = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.unsubscribe = function(callback) { - this._community.unsubscribeSharedfileComments(this.owner, this.id, callback); + this._community.unsubscribeSharedfileComments(this.owner, this.id, callback); }; /** @@ -189,7 +211,7 @@ CSteamSharedfile.prototype.unsubscribe = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.voteDown = function(callback) { - this._community.voteDownSharedfile(this.id, callback); + this._community.voteDownSharedfile(this.id, callback); }; /** @@ -197,5 +219,5 @@ CSteamSharedfile.prototype.voteDown = function(callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ CSteamSharedfile.prototype.voteUp = function(callback) { - this._community.voteUpSharedfile(this.id, callback); + this._community.voteUpSharedfile(this.id, callback); }; \ No newline at end of file diff --git a/components/sharedfiles.js b/components/sharedfiles.js index be9fe3a..3ef690a 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -10,24 +10,24 @@ var SteamID = require('steamid'); * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, callback) { - if (typeof userID === "string") { - userID = new SteamID(userID); - } - - this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/delete/${userID.toString()}/${sid}/`, - "form": { - "gidcomment": cid, - "count": 10, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/delete/${userID.toString()}/${sid}/`, + "form": { + "gidcomment": cid, + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -37,20 +37,20 @@ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, ca * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.favoriteSharedfile = function(sid, appid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/favorite", - "form": { - "id": sid, - "appid": appid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/favorite", + "form": { + "id": sid, + "appid": appid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -61,24 +61,24 @@ SteamCommunity.prototype.favoriteSharedfile = function(sid, appid, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, callback) { - if (typeof userID === "string") { - userID = new SteamID(userID); - } - - this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/post/${userID.toString()}/${sid}/`, - "form": { - "comment": message, - "count": 10, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/post/${userID.toString()}/${sid}/`, + "form": { + "comment": message, + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -88,23 +88,23 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, callback) { - if (typeof userID === "string") { - userID = new SteamID(userID); - } - - this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/subscribe/${userID.toString()}/${sid}/`, - "form": { - "count": 10, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { // eslint-disable-line - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/subscribe/${userID.toString()}/${sid}/`, + "form": { + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { // eslint-disable-line + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -114,20 +114,20 @@ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, cal * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/unfavorite", - "form": { - "id": sid, - "appid": appid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/unfavorite", + "form": { + "id": sid, + "appid": appid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -137,23 +137,23 @@ SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { - if (typeof userID === "string") { - userID = new SteamID(userID); - } - - this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/unsubscribe/${userID.toString()}/${sid}/`, - "form": { - "count": 10, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { // eslint-disable-line - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + if (typeof userID === "string") { + userID = new SteamID(userID); + } + + this.httpRequestPost({ + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/unsubscribe/${userID.toString()}/${sid}/`, + "form": { + "count": 10, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { // eslint-disable-line + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -162,19 +162,19 @@ SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, c * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.voteDownSharedfile = function(sid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/votedown", - "form": { - "id": sid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/votedown", + "form": { + "id": sid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; /** @@ -183,17 +183,17 @@ SteamCommunity.prototype.voteDownSharedfile = function(sid, callback) { * @param {function} callback - Takes only an Error object/null as the first argument */ SteamCommunity.prototype.voteUpSharedfile = function(sid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/voteup", - "form": { - "id": sid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); + this.httpRequestPost({ + "uri": "https://steamcommunity.com/sharedfiles/voteup", + "form": { + "id": sid, + "sessionid": this.getSessionID() + } + }, function(err, response, body) { + if (!callback) { + return; + } + + callback(null || err); + }, "steamcommunity"); }; \ No newline at end of file diff --git a/resources/ESharedfileType.js b/resources/ESharedfileType.js index b8732ce..fc528d5 100644 --- a/resources/ESharedfileType.js +++ b/resources/ESharedfileType.js @@ -2,12 +2,12 @@ * @enum ESharedfileType */ module.exports = { - "Screenshot": 0, - "Artwork": 1, - "Guide": 2, + "Screenshot": 0, + "Artwork": 1, + "Guide": 2, - // Value-to-name mapping for convenience - "0": "Screenshot", - "1": "Artwork", - "2": "Guide" + // Value-to-name mapping for convenience + "0": "Screenshot", + "1": "Artwork", + "2": "Guide" }; \ No newline at end of file From 4723bd93a61a8aae0cf725d8d452fab3577173a3 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Mon, 15 May 2023 22:27:37 +0200 Subject: [PATCH 16/22] Improve resolveVanityURL() and move to helpers --- components/helpers.js | 40 ++++++++++++++++++++++++++++++++++ components/inventoryhistory.js | 19 ++-------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/components/helpers.js b/components/helpers.js index 1da5443..b354da5 100644 --- a/components/helpers.js +++ b/components/helpers.js @@ -1,4 +1,6 @@ const EResult = require('../resources/EResult.js'); +const request = require('request'); +const xml2js = require('xml2js'); exports.isSteamID = function(input) { var keys = Object.keys(input); @@ -54,3 +56,41 @@ exports.eresultError = function(eresult) { err.eresult = eresult; return err; }; + +/** + * Resolves a Steam profile URL to get steamID64 and vanityURL + * @param {String} url - Full steamcommunity profile URL or only the vanity part. + * @param {Object} callback - First argument is null/Error, second is object containing vanityURL (String) and steamID (String) + */ +exports.resolveVanityURL = function(url, callback) { + // Precede url param if only the vanity was provided + if (!url.includes("steamcommunity.com")) { + url = "https://steamcommunity.com/id/" + url; + } + + // Make request to get XML data + request(url + "/?xml=1", function(err, response, body) { + if (err) { + callback(err); + return; + } + + // Parse XML data returned from Steam into an object + new xml2js.Parser().parseString(body, (err, parsed) => { + if (err) { + callback(new Error("Couldn't parse XML response")); + return; + } + + if (parsed.response && parsed.response.error) { + callback(new Error("Couldn't find Steam ID")); + return; + } + + let steamID64 = parsed.profile.steamID64; + let vanityURL = parsed.profile.customURL; + + callback(null, {"vanityURL": vanityURL, "steamID": steamID64}); + }); + }); +}; \ No newline at end of file diff --git a/components/inventoryhistory.js b/components/inventoryhistory.js index fd7c522..961d9c1 100644 --- a/components/inventoryhistory.js +++ b/components/inventoryhistory.js @@ -1,5 +1,6 @@ var SteamCommunity = require('../index.js'); var CEconItem = require('../classes/CEconItem.js'); +var Helpers = require('./helpers.js'); var SteamID = require('steamid'); var request = require('request'); var Cheerio = require('cheerio'); @@ -142,7 +143,7 @@ SteamCommunity.prototype.getInventoryHistory = function(options, callback) { } if (options.resolveVanityURLs) { - Async.map(vanityURLs, resolveVanityURL, function(err, results) { + Async.map(vanityURLs, Helpers.resolveVanityURL, function(err, results) { if (err) { callback(err); return; @@ -170,19 +171,3 @@ SteamCommunity.prototype.getInventoryHistory = function(options, callback) { }, "steamcommunity"); }; -function resolveVanityURL(vanityURL, callback) { - request("https://steamcommunity.com/id/" + vanityURL + "/?xml=1", function(err, response, body) { - if (err) { - callback(err); - return; - } - - var match = body.match(/(\d+)<\/steamID64>/); - if (!match || !match[1]) { - callback(new Error("Couldn't find Steam ID")); - return; - } - - callback(null, {"vanityURL": vanityURL, "steamID": match[1]}); - }); -} From 27d2daac61113dddef2ece07bc4a58a72f6ec12e Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Mon, 15 May 2023 22:35:39 +0200 Subject: [PATCH 17/22] Remove steamid-resolver dep and use internal helper --- classes/CSteamSharedfile.js | 7 +++---- package.json | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 8ed43ad..8401cd6 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -2,14 +2,13 @@ const Cheerio = require('cheerio'); const SteamID = require('steamid'); const Helpers = require('../components/helpers.js'); const SteamCommunity = require('../index.js'); -const SteamIdResolver = require('steamid-resolver'); const ESharedfileType = require('../resources/ESharedfileType.js'); /** * Scrape a sharedfile's DOM to get all available information * @param {String} sid - ID of the sharedfile - * @param {function} callback - First argument is null/Error, second is object containing all available information + * @param {function} callback - First argument is null/Error, second is object containing all available information */ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { @@ -123,9 +122,9 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { // Find owner profile link, convert to steamID64 using SteamIdResolver lib and create a SteamID object let ownerHref = $(".friendBlockLinkOverlay").attr()["href"]; - SteamIdResolver.customUrlToSteamID64(ownerHref, (err, steamID64) => { // This request takes <1 sec + Helpers.resolveVanityURL(ownerHref, (err, data) => { // This request takes <1 sec if (!err) { - sharedfile.owner = new SteamID(steamID64); + sharedfile.owner = new SteamID(data.steamID); } // Make callback when ID was resolved as otherwise owner will always be null diff --git a/package.json b/package.json index 64709eb..afd186a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "request": "^2.88.0", "steam-totp": "^1.5.0", "steamid": "^1.1.3", - "steamid-resolver": "^1.2.3", "xml2js": "^0.4.22" }, "engines": { From f7d7cf0660c5a15fc24ca770afeb3f9e40936403 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Mon, 15 May 2023 22:42:22 +0200 Subject: [PATCH 18/22] Remove support for up- & downvoting sharedfiles --- classes/CSteamSharedfile.js | 16 -------------- components/sharedfiles.js | 42 ------------------------------------- 2 files changed, 58 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 8401cd6..432f09a 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -204,19 +204,3 @@ CSteamSharedfile.prototype.unfavorite = function(callback) { CSteamSharedfile.prototype.unsubscribe = function(callback) { this._community.unsubscribeSharedfileComments(this.owner, this.id, callback); }; - -/** - * Downvotes this sharedfile - * @param {function} callback - Takes only an Error object/null as the first argument - */ -CSteamSharedfile.prototype.voteDown = function(callback) { - this._community.voteDownSharedfile(this.id, callback); -}; - -/** - * Upvotes this sharedfile - * @param {function} callback - Takes only an Error object/null as the first argument - */ -CSteamSharedfile.prototype.voteUp = function(callback) { - this._community.voteUpSharedfile(this.id, callback); -}; \ No newline at end of file diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 3ef690a..00a754c 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -155,45 +155,3 @@ SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, c callback(null || err); }, "steamcommunity"); }; - -/** - * Downvotes a sharedfile - * @param {String} sid - ID of the sharedfile - * @param {function} callback - Takes only an Error object/null as the first argument - */ -SteamCommunity.prototype.voteDownSharedfile = function(sid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/votedown", - "form": { - "id": sid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); -}; - -/** - * Upvotes a sharedfile - * @param {String} sid - ID of the sharedfile - * @param {function} callback - Takes only an Error object/null as the first argument - */ -SteamCommunity.prototype.voteUpSharedfile = function(sid, callback) { - this.httpRequestPost({ - "uri": "https://steamcommunity.com/sharedfiles/voteup", - "form": { - "id": sid, - "sessionid": this.getSessionID() - } - }, function(err, response, body) { - if (!callback) { - return; - } - - callback(null || err); - }, "steamcommunity"); -}; \ No newline at end of file From f96d25ad52cb65b3355bea7b25b8aee597728206 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Mon, 15 May 2023 22:45:33 +0200 Subject: [PATCH 19/22] Rename sid to sharedFileId --- classes/CSteamSharedfile.js | 10 +++++----- components/sharedfiles.js | 36 ++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 432f09a..80d2a85 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -7,14 +7,14 @@ const ESharedfileType = require('../resources/ESharedfileType.js'); /** * Scrape a sharedfile's DOM to get all available information - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {function} callback - First argument is null/Error, second is object containing all available information */ -SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { +SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { // Construct object holding all the data we can scrape let sharedfile = { - id: sid, + id: sharedFileId, type: null, appID: null, owner: null, @@ -28,7 +28,7 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { // Get DOM of sharedfile - this.httpRequestGet(`https://steamcommunity.com/sharedfiles/filedetails/?id=${sid}`, (err, res, body) => { + this.httpRequestGet(`https://steamcommunity.com/sharedfiles/filedetails/?id=${sharedFileId}`, (err, res, body) => { try { /* --------------------- Preprocess output --------------------- */ @@ -66,7 +66,7 @@ SteamCommunity.prototype.getSteamSharedfile = function(sid, callback) { /* --------------------- Find and map values --------------------- */ // Find appID in share button onclick event - sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sid}', '`, "").replace("' );", "")); + sharedfile.appID = Number($("#ShareItemBtn").attr()["onclick"].replace(`ShowSharePublishedFilePopup( '${sharedFileId}', '`, "").replace("' );", "")); // Find fileSize if not guide diff --git a/components/sharedfiles.js b/components/sharedfiles.js index 00a754c..c051943 100644 --- a/components/sharedfiles.js +++ b/components/sharedfiles.js @@ -5,17 +5,17 @@ var SteamID = require('steamid'); /** * Deletes a comment from a sharedfile's comment section * @param {SteamID | String} userID - ID of the user associated to this sharedfile - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {String} cid - ID of the comment to delete * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, callback) { +SteamCommunity.prototype.deleteSharedfileComment = function(userID, sharedFileId, cid, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/delete/${userID.toString()}/${sid}/`, + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/delete/${userID.toString()}/${sharedFileId}/`, "form": { "gidcomment": cid, "count": 10, @@ -32,15 +32,15 @@ SteamCommunity.prototype.deleteSharedfileComment = function(userID, sid, cid, ca /** * Favorites a sharedfile - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {String} appid - ID of the app associated to this sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.favoriteSharedfile = function(sid, appid, callback) { +SteamCommunity.prototype.favoriteSharedfile = function(sharedFileId, appid, callback) { this.httpRequestPost({ "uri": "https://steamcommunity.com/sharedfiles/favorite", "form": { - "id": sid, + "id": sharedFileId, "appid": appid, "sessionid": this.getSessionID() } @@ -56,17 +56,17 @@ SteamCommunity.prototype.favoriteSharedfile = function(sid, appid, callback) { /** * Posts a comment to a sharedfile * @param {SteamID | String} userID - ID of the user associated to this sharedfile - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {String} message - Content of the comment to post * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, callback) { +SteamCommunity.prototype.postSharedfileComment = function(userID, sharedFileId, message, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/post/${userID.toString()}/${sid}/`, + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/post/${userID.toString()}/${sharedFileId}/`, "form": { "comment": message, "count": 10, @@ -84,16 +84,16 @@ SteamCommunity.prototype.postSharedfileComment = function(userID, sid, message, /** * Subscribes to a sharedfile's comment section. Note: Checkbox on webpage does not update * @param {SteamID | String} userID ID of the user associated to this sharedfile - * @param {String} sid ID of the sharedfile + * @param {String} sharedFileId ID of the sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, callback) { +SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sharedFileId, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/subscribe/${userID.toString()}/${sid}/`, + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/subscribe/${userID.toString()}/${sharedFileId}/`, "form": { "count": 10, "sessionid": this.getSessionID() @@ -109,15 +109,15 @@ SteamCommunity.prototype.subscribeSharedfileComments = function(userID, sid, cal /** * Unfavorites a sharedfile - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {String} appid - ID of the app associated to this sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { +SteamCommunity.prototype.unfavoriteSharedfile = function(sharedFileId, appid, callback) { this.httpRequestPost({ "uri": "https://steamcommunity.com/sharedfiles/unfavorite", "form": { - "id": sid, + "id": sharedFileId, "appid": appid, "sessionid": this.getSessionID() } @@ -133,16 +133,16 @@ SteamCommunity.prototype.unfavoriteSharedfile = function(sid, appid, callback) { /** * Unsubscribes from a sharedfile's comment section. Note: Checkbox on webpage does not update * @param {SteamID | String} userID - ID of the user associated to this sharedfile - * @param {String} sid - ID of the sharedfile + * @param {String} sharedFileId - ID of the sharedfile * @param {function} callback - Takes only an Error object/null as the first argument */ -SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sid, callback) { +SteamCommunity.prototype.unsubscribeSharedfileComments = function(userID, sharedFileId, callback) { if (typeof userID === "string") { userID = new SteamID(userID); } this.httpRequestPost({ - "uri": `https://steamcommunity.com/comment/PublishedFile_Public/unsubscribe/${userID.toString()}/${sid}/`, + "uri": `https://steamcommunity.com/comment/PublishedFile_Public/unsubscribe/${userID.toString()}/${sharedFileId}/`, "form": { "count": 10, "sessionid": this.getSessionID() From 33bc8d83c93ad3d26da657ad0b3fb2ea22de9d0b Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 28 May 2023 13:45:00 +0200 Subject: [PATCH 20/22] Add support for determining up/downvote status --- classes/CSteamSharedfile.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 80d2a85..6935787 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -23,7 +23,9 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { resolution: null, uniqueVisitorsCount: null, favoritesCount: null, - upvoteCount: null + upvoteCount: null, + isUpvoted: null, + isDownvoted: null }; @@ -103,6 +105,11 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { } + // Determine if this account has already voted on this sharedfile + sharedfile.isUpvoted = String($(".workshopItemControlCtn > #VoteUpBtn")[0].attribs["class"]).includes("toggled"); // Check if upvote btn class contains "toggled" + sharedfile.isDownvoted = String($(".workshopItemControlCtn > #VoteDownBtn")[0].attribs["class"]).includes("toggled"); // Check if downvote btn class contains "toggled" + + // Determine type by looking at the second breadcrumb. Find the first separator as it has a unique name and go to the next element which holds our value of interest let breadcrumb = $(".breadcrumbs > .breadcrumb_separator").next().get(0).children[0].data || ""; From e23fa02c91efe792b6e0bf9e3ca37a35fc236e17 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Sun, 28 May 2023 14:02:40 +0200 Subject: [PATCH 21/22] Add support for reading numRatings of guides --- classes/CSteamSharedfile.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 6935787..2523b48 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -24,6 +24,7 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { uniqueVisitorsCount: null, favoritesCount: null, upvoteCount: null, + guideNumRatings: null, isUpvoted: null, isDownvoted: null }; @@ -105,6 +106,12 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { } + // Find numRatings if this is a guide as they use a different voting system + let numRatings = $(".ratingSection > .numRatings").text().replace(" ratings", "") + + sharedfile.guideNumRatings = Number(numRatings) || null; // Set to null if not a guide or if the guide does not have enough ratings to show a value + + // Determine if this account has already voted on this sharedfile sharedfile.isUpvoted = String($(".workshopItemControlCtn > #VoteUpBtn")[0].attribs["class"]).includes("toggled"); // Check if upvote btn class contains "toggled" sharedfile.isDownvoted = String($(".workshopItemControlCtn > #VoteDownBtn")[0].attribs["class"]).includes("toggled"); // Check if downvote btn class contains "toggled" From 440b2f9ba98f0c9d3be243b379a3def367ce7dd9 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Mon, 29 May 2023 19:29:24 +0200 Subject: [PATCH 22/22] Add JsDoc --- classes/CSteamSharedfile.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/classes/CSteamSharedfile.js b/classes/CSteamSharedfile.js index 2523b48..889039a 100644 --- a/classes/CSteamSharedfile.js +++ b/classes/CSteamSharedfile.js @@ -107,7 +107,7 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { // Find numRatings if this is a guide as they use a different voting system - let numRatings = $(".ratingSection > .numRatings").text().replace(" ratings", "") + let numRatings = $(".ratingSection > .numRatings").text().replace(" ratings", ""); sharedfile.guideNumRatings = Number(numRatings) || null; // Set to null if not a guide or if the guide does not have enough ratings to show a value @@ -151,22 +151,20 @@ SteamCommunity.prototype.getSteamSharedfile = function(sharedFileId, callback) { }, "steamcommunity"); }; +/** + * Constructor - Creates a new Sharedfile object + * @class + * @param {SteamCommunity} community + * @param {{ id: string, type: ESharedfileType, appID: number, owner: SteamID|null, fileSize: string|null, postDate: number, resolution: string|null, uniqueVisitorsCount: number, favoritesCount: number, upvoteCount: number|null, guideNumRatings: Number|null, isUpvoted: boolean, isDownvoted: boolean }} data + */ function CSteamSharedfile(community, data) { + /** + * @type {SteamCommunity} + */ this._community = community; // Clone all the data we recieved - Object.assign(this, data); // TODO: This is cleaner but might break IntelliSense. I'm leaving the block below to be reactivated if necessary - - /* this.id = data.id; - this.type = data.type; - this.appID = data.appID; - this.owner = data.owner; - this.fileSize = data.fileSize; - this.postDate = data.postDate; - this.resolution = data.resolution; - this.uniqueVisitorsCount = data.uniqueVisitorsCount; - this.favoritesCount = data.favoritesCount; - this.upvoteCount = data.upvoteCount; */ + Object.assign(this, data); } /**