steamutils 1.0.0
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.
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/steamutils.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/axios.js +91 -0
- package/cheerio.js +71 -0
- package/example.js +12 -0
- package/index.js +4065 -0
- package/package.json +16 -0
- package/string.js +96 -0
- package/utils.js +100 -0
- package/xml2json.js +50 -0
package/index.js
ADDED
@@ -0,0 +1,4065 @@
|
|
1
|
+
import cheerio from 'cheerio'
|
2
|
+
import {randomBytes} from 'crypto'
|
3
|
+
import sha256 from 'crypto-js/sha256.js'
|
4
|
+
import _ from 'lodash'
|
5
|
+
import moment from 'moment'
|
6
|
+
import {hex2b64, Key as RSA} from 'node-bignumber'
|
7
|
+
import SteamID from 'steamid'
|
8
|
+
import URL from 'url'
|
9
|
+
import Url from 'url-parse'
|
10
|
+
import xml2js from 'xml2js'
|
11
|
+
import {JSON_parse, JSON_stringify, console_log, getCleanObject, removeSpaceKeys, sleep} from './utils.js'
|
12
|
+
import './string.js'
|
13
|
+
import {Header, request} from './axios.js'
|
14
|
+
import {getTableHasHeaders, table2json} from './cheerio.js'
|
15
|
+
import {getJSObjectFronXML} from './xml2json.js'
|
16
|
+
|
17
|
+
const MAX_RETRY = 10
|
18
|
+
export const MatchHistoryType = {
|
19
|
+
matchhistoryscrimmage: 'matchhistoryscrimmage',
|
20
|
+
matchhistorycompetitive: 'matchhistorycompetitive',
|
21
|
+
}
|
22
|
+
|
23
|
+
export const MatchWinLose = {
|
24
|
+
Win: 'Win',
|
25
|
+
Lose: 'Lose',
|
26
|
+
Tie: 'Tie',
|
27
|
+
}
|
28
|
+
export const AppID_CSGO = 730
|
29
|
+
const SteamcommunityURL = 'https://steamcommunity.com'
|
30
|
+
|
31
|
+
const FRIEND_CODE_REPLACEMENTS = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 't', 'v', 'w']
|
32
|
+
|
33
|
+
const EPrivacyState = {
|
34
|
+
Private: 'Private',
|
35
|
+
FriendsOnly: 'FriendsOnly',
|
36
|
+
Public: 'Public'
|
37
|
+
}
|
38
|
+
const EActivityType = Object.freeze({
|
39
|
+
newFriend: 'newFriend',
|
40
|
+
playedFirstTime: 'playedFirstTime',
|
41
|
+
achieved: 'achieved',
|
42
|
+
added2wishlist: 'added2wishlist',
|
43
|
+
following: 'following',
|
44
|
+
joined: 'joined',
|
45
|
+
own: 'own',
|
46
|
+
})
|
47
|
+
|
48
|
+
const PrivacySettings = {
|
49
|
+
profile: 'Public',
|
50
|
+
inventory: 'Public',
|
51
|
+
inventoryGifts: 'Private',
|
52
|
+
gameDetails: 'Public',
|
53
|
+
playtime: 'Public',
|
54
|
+
friendsList: 'Public',
|
55
|
+
comment: 'Private'
|
56
|
+
}
|
57
|
+
|
58
|
+
const EFriendRelationship = {
|
59
|
+
None: 0,
|
60
|
+
Blocked: 1,
|
61
|
+
RequestRecipient: 2,
|
62
|
+
Friend: 3,
|
63
|
+
RequestInitiator: 4,
|
64
|
+
Ignored: 5,
|
65
|
+
IgnoredFriend: 6,
|
66
|
+
SuggestedFriend: 7, // removed "was used by the original implementation of the facebook linking feature; but now unused."
|
67
|
+
|
68
|
+
// Value-to-name mapping for convenience
|
69
|
+
0: 'None',
|
70
|
+
1: 'Blocked',
|
71
|
+
2: 'RequestRecipient',
|
72
|
+
3: 'Friend',
|
73
|
+
4: 'RequestInitiator',
|
74
|
+
5: 'Ignored',
|
75
|
+
6: 'IgnoredFriend',
|
76
|
+
7: 'SuggestedFriend',
|
77
|
+
}
|
78
|
+
|
79
|
+
const EGroupRank = Object.freeze({
|
80
|
+
Owner: ['Group Owner', 'Ιδιοκτήτης ομάδας', 'Groepseigenaar', 'Gruppeeier', 'Gruppeejer', 'Gruppenbesitzer', 'Владелец группы', 'Proprietarul grupului', 'Chủ sở hữu nhóm', 'Собственик на групата', 'Gruppägare', 'Propietario del grupo', 'Власник групи', 'Proprietario del gruppo', 'グループのオーナー', '组所有者', '群組擁有者', 'Vlastník skupiny', 'เจ้าของกลุ่ม', 'Grubun Sahibi', 'Dono do grupo', 'Proprietário do grupo', 'Właściciel grupy', 'Propriétaire du groupe', 'Omistaja', '그룹 소유자', 'Csoporttulajdonos'],
|
81
|
+
Officer: ['Group Officer', 'Διαχειριστής ομάδας', 'Groepsbeheerder', 'Gruppeoffiser', 'Gruppeofficer', 'Gruppenadministrator', 'Офицер группы', 'Ofițer de grup', 'Ủy viên nhóm', 'Офицер на групата', 'Gruppofficer', 'Oficial del grupo', 'Адміністратор групи', 'Amministratore del gruppo', 'グループの上級メンバー', '组官员', '群組幹部', 'Správce skupiny', 'เจ้าหน้าที่กลุ่ม', 'Grup Yetkilisi', 'Administrador do grupo', 'Oficial de Grupo', 'Oficer grupy', 'Responsable du groupe', 'Ylläpitäjä', '그룹 임원', 'Csoport-elöljáró'],
|
82
|
+
Moderator: ['Group Moderator', 'Συντονιστής ομάδας', 'Groepsmoderator', 'Gruppemoderator', 'Gruppenmoderator', 'Модератор группы', 'Moderator de grup', 'Điều hành viên nhóm', 'Модератор на групата', 'Gruppmoderator', 'Moderador del grupo', 'Модератор групи', 'Moderatore del gruppo', 'グループのモデレーター', '组版主', '群組板務', 'Moderátor skupiny', 'ผู้ช่วยดูแลกลุ่ม', 'Grup Moderatörü', 'Moderador do grupo', 'Moderador de Grupo', 'Moderator grupy', 'Modération du groupe', 'Valvoja', '그룹 모더레이터', 'Csoportmoderátor'],
|
83
|
+
})
|
84
|
+
|
85
|
+
const ELanguage = Object.freeze({
|
86
|
+
greek: 'greek',
|
87
|
+
dutch: 'dutch',
|
88
|
+
norwegian: 'norwegian',
|
89
|
+
danish: 'danish',
|
90
|
+
german: 'german',
|
91
|
+
russian: 'russian',
|
92
|
+
romanian: 'romanian',
|
93
|
+
vietnamese: 'vietnamese',
|
94
|
+
bulgarian: 'bulgarian',
|
95
|
+
swedish: 'swedish',
|
96
|
+
spanish: 'spanish',
|
97
|
+
latam: 'latam',
|
98
|
+
english: 'english',
|
99
|
+
ukrainian: 'ukrainian',
|
100
|
+
italian: 'italian',
|
101
|
+
japanese: 'japanese',
|
102
|
+
schinese: 'schinese',
|
103
|
+
tchinese: 'tchinese',
|
104
|
+
czech: 'czech',
|
105
|
+
thai: 'thai',
|
106
|
+
turkish: 'turkish',
|
107
|
+
brazilian: 'brazilian',
|
108
|
+
portuguese: 'portuguese',
|
109
|
+
polish: 'polish',
|
110
|
+
french: 'french',
|
111
|
+
finnish: 'finnish',
|
112
|
+
koreana: 'koreana',
|
113
|
+
hungarian: 'hungarian'
|
114
|
+
})
|
115
|
+
|
116
|
+
export const NotYetSetupProfileTextList = Object.freeze(['This user has not yet set up their Steam Community profile.If you know this person, encourage them to set up their profile and join in the gaming!', 'Αυτός ο χρήστης δεν έχει ρυθμίσει το προφίλ του στην Κοινότητα του Steam.Αν τον γνωρίζετε, ενθαρρύνετέ τον να στήσει το προφίλ του και να συμμετάσχει στο παιχνίδι!', 'Deze gebruiker heeft nog geen Steam-communityprofiel.Als je deze persoon kent, moedig hem of haar dan aan om een profiel te maken en deel te nemen aan de gamingcommunity!', 'Denne brukeren har ikke satt opp Steam-samfunnsprofilen.Hvis du kjenner denne personen, kan du oppmuntre vedkommende til å sette opp profilen og bli med på spillingen!', 'Denne bruger har endnu ikke tilpasset sin profil på Steam-fællesskabet.Hvis du kender vedkommende, så få dem til at tilpasse deres profil og deltage i spilfællesskabet!', 'Diese Person hat ihr Steam-Communityprofil noch nicht eingerichtet.Wenn Sie diese Person kennen, fordern Sie sie doch auf, ihr Profil einzurichten und an der Spielecommunity teilzunehmen!', 'Этот пользователь ещё не настроил свой профиль в сообществе Steam.Если вы знакомы, посоветуйте ему настроить профиль, чтобы играть вместе!', 'Acest utilizator nu și-a configurat încă profilul din comunitatea Steam.Dacă cunoști această persoană, încurajeaz-o să-și configureze un profil și să se alăture comunității!', 'Người dùng này vẫn chưa thiết lập hồ sơ cộng đồng Steam.Nếu là người bạn quen, hãy khuyến khích người ấy thiết lập hồ sơ và cùng chơi!', 'Този потребител все още не е настроил своя профил за Steam общността.Ако познавате това лице, насърчете го да установи своя профил и да се присъедини към игралното преживяване!', 'Den här användaren har inte lagt upp sin gemenskapsprofil på Steam.Uppmuntra hen att lägga upp en profil och börja spela, om du känner personen!', 'Este/a usuario/a aún no ha configurado su perfil de la Comunidad Steam.Si conoces a esta persona, anímala a configurar su perfil para unirse a la fiesta.', 'Este usuario aún no ha configurado su perfil de la Comunidad Steam.Si lo conoces, anímale a configurar su perfil para unirse a la fiesta.', 'This user has not yet set up their Steam Community profile.If you know this person, encourage them to set up their profile and join in the gaming!', 'Цей користувач ще не налаштував свій профіль спільноти Steam. Якщо ви знайомі, то порадьте йому/їй налаштувати свій профіль і почати грати!', 'Questo utente non ha ancora configurato il suo profilo della Comunità di Steam.Se lo conosci, invitalo a configurare il suo profilo e unirsi al divertimento!', 'このユーザーはまだSteamコミュニティのプロフィールを作成していません。このユーザーを知っている場合は、プロフィールを作成してゲーマーとして参加するよう伝えてみましょう。', '此用户尚未设置自己的 Steam 社区个人资料。如果您认识此人,请鼓励对方设置个人资料并加入到游戏当中!', '這位使用者尚未設定 Steam 社群個人檔案。如果您認識對方,請鼓勵他設定個人檔案,並加入遊戲世界!', 'Tento uživatel si zatím nenastavil svůj profil v komunitě služby Steam.Pokud tohoto uživatele znáte, napište mu, aby si nastavil svůj profil a stal se tak opravdovým členem komunity!', 'ผู้ใช้นี้ยังไม่ได้ตั้งค่าโปรไฟล์ชุมชน Steamหากคุณรู้จักผู้ใช้นี้ บอกให้เขาตั้งค่าโปรไฟล์ แล้วมาเล่นเกมด้วยกัน!', 'Bu kullanıcı Steam Topluluğu profilini henüz oluşturmadı.Eğer bu kullanıcıyı tanıyorsanız, profilini oluşturmasını ve oyun dünyasına katılmasını sağlayın!', 'Esse(a) usuário(a) ainda não criou um perfil da Comunidade Steam.Caso o(a) conheça, encoraje-o(a) a criá-lo e jogar com você!', 'Esta pessoa ainda não configurou o seu perfil na Comunidade Steam.Se conheces esta pessoa, encoraja-a a configurar um perfil e a jogar contigo!', 'Ten użytkownik jeszcze nie uzupełnił swojego profilu Społeczności Steam.Jeżeli to twój znajomy, zachęć go, żeby to zrobił.', 'Cette personne n’a pas encore de profil dans la communauté Steam.Si vous la connaissez, encouragez-la à créer un profil et à rejoindre des parties !', 'Käyttäjä ei ole vielä luonut Steam-yhteisön profiilia.Jos tunnet hänet, kehota häntä luomaan profiili ja liittymään peliyhteisöön.', '이 사용자는 아직 Steam 커뮤니티 프로필을 설정하지 않았습니다.이 사용자를 알고 계시면 프로필을 설정하고 게임에 참가하도록 권해 주십시오!', 'Ez a felhasználó még nem állította be Steam közösségi profilját.Ha az ismerősöd, bátorítsd, hogy állítsa be profilját, és vegyen részt a játékban!'])
|
117
|
+
export const PrivateProfileTextList = Object.freeze(['This profile is private.', 'Αυτό το προφίλ είναι ιδιωτικό.', 'Dit is een privéprofiel', 'Denne profilen er privat.', 'Denne profil er privat.', 'Dieses Profil ist privat.', 'Профиль скрыт', 'Acest profil este privat.', 'Hồ sơ này không công khai.', 'Този профил е личен.', 'Den här profilen är privat.', 'Este perfil es privado.', 'Este perfil es privado.', 'This profile is private.', 'Профіль приховано', 'Questo profilo è privato.', 'プロフィールは非公開に設定されています。', '此个人资料是私密的。', '此個人檔案未公開。', 'Tento profil je soukromý.', 'โปรไฟล์นี้เป็นโปรไฟล์ส่วนตัว', 'Bu profil gizlidir.', 'Este perfil é privado.', 'Este perfil é privado.', 'Ten profil jest prywatny.', 'Ce profil est privé.', 'Tämä profiili on yksityinen.', '이 프로필은 비공개입니다.', 'Privát profil.'])
|
118
|
+
const ErrorProcessingRequest = Object.freeze(['An error was encountered while processing your request:', 'Παρουσιάστηκε σφάλμα κατά την επεξεργασία του αιτήματός σας:', 'Er is een fout opgetreden bij het verwerken van je verzoek.', 'Det oppstod en feil under behandling av forespørselen:', 'Der skete en fejl ved behandling af din forespørgsel:', 'Bei der Verarbeitung Ihrer Anfrage ist ein Fehler aufgetreten:', 'При обработке вашего запроса произошла ошибка:', 'A apărut o eroare în timpul procesării:', 'Đã có lỗi xảy ra trong quá trình xử lí yêu cầu của bạn:', 'Възникна грешка, докато обработвахме заявката Ви:', 'Ett fel uppstod när din begäran behandlades:', 'Se ha producido un error mientras se procesaba la solicitud:', 'Se ha producido un error mientras se procesaba la solicitud:', 'An error was encountered while processing your request:', 'Під час обробки вашого запиту сталася помилка:', 'Si è verificato un errore durante l\'elaborazione della tua richiesta:', 'リクエストの処理中にエラーが発生しました。', '处理您的请求时遇到错误:', '處理您的要求時發生錯誤:', 'Při zpracovávání Vašeho požadavku došlo k chybě:', 'ตรวจพบข้อผิดพลาดขณะกำลังประมวลผลคำร้องขอของคุณ:', 'İşleminiz sırasında bir hata meydana geldi:', 'Ocorreu um erro ao processar a sua solicitação:', 'Foi encontrado um erro ao processar o pedido', 'Wystąpił błąd przetwarzania żądania użytkownika:', 'Une erreur est survenue lors du traitement de votre requête :', 'Pyyntösi käsittelyssä tapahtui virhe:', '요청을 처리하는 동안 오류가 발생했습니다.', 'Hiba lépett fel a kérésed feldolgozása közben:'])
|
119
|
+
export const EmptyProfileSummary = Object.freeze(['No information given.', 'Δεν έχουν δοθεί πληροφορίες.', 'Geen informatie gegeven.', 'Ingen informasjon oppgitt.', 'Ingen oplysninger.', 'Keine Informationen angegeben.', 'Информация отсутствует.', 'Nicio informație oferită.', 'Không có thông tin nào được cấp.', 'Няма предоставена информация.', 'Information saknas.', 'No se ha proporcionado información.', 'No se ha proporcionado información.', 'No information given.', 'Не надано жодної інформації.', 'Nessuna informazione.', '情報が指定されていません。', '未提供信息。', '未提供任何資訊。', 'Nebyly zadány žádné informace.', 'ไม่ระบุข้อมูล', 'Herhangi bir bilgi verilmedi.', 'Nada informado.', 'Sem informações.', 'Nie podano informacji.', 'Aucune information disponible.', 'Ei tietoja.', '관련 정보가 없습니다.', 'Nincs információ.'])
|
120
|
+
const ECurrentlyTradeBanned = Object.freeze(['Currently trade banned', 'Αποκλεισμένος από ανταλλαγές', 'Heeft momenteel ruilban', 'For øyeblikket utestengt fra byttehandel', 'I øjeblikket udelukket fra at bytte', 'Zurzeit vom Handel ausgeschlossen', 'Заблокирован в системе обмена', 'În prezent, abilitate de schimb este banată', 'Hiện đang bị cấm trao đổi', 'Понастоящем със забрана за търгуване', 'Har för närvarande bytesförbud', 'Intercambio actualmente bloqueado', 'Intercambio actualmente bloqueado', 'Currently trade banned', 'Наразі обмін заблоковано', 'Attualmente bandito dagli scambi', '現在トレード禁止', '当前已禁止交易', '目前已遭交易封鎖', 'Momentálně má zakázáno obchodovat', 'ถูกแบนการแลกเปลี่ยนอยู่ในขณะนี้', 'Şu anda takas yasaklı', 'Banido de trocar', 'Banido do sistema de trocas', 'Wymiana obecnie zablokowana', 'Actuellement interdit d\'échange', 'Vaihtokiellossa', '거래 차단 상태', 'Jelenleg kitiltva a cseréből'])
|
121
|
+
const E1VACBanOnRecord = Object.freeze(['1 VAC ban on record | Info', '1 αποκλεισμός VAC στο αρχείο | Πληροφορίες', '1 vastgelegde VAC-verbanning | Info', '1 VAC-utestengelse registrert | Info', '1 VAC-udelukkelse registreret | Info', '1 VAC-Ausschluss | Informationen', '1 блокировка VAC | Подробнее', '1 banare VAC înregistrată | Informații', '1 lệnh cấm VAC được ghi nhận | Thông tin', '1 вписана VAC забрана | Информация', '1 registrerad VAC-avstängning | Info', '1 bloqueo por VAC registrado | Detalles', '1 bloqueo por VAC registrado | Detalles', '1 VAC ban on record | Info', '1 зареєстроване блокування VAC | Інформація', '1 ban VAC registrato | Informazioni', '1 件の VAC 検出記録 | 情報', '1 个记录在案的 VAC 封禁 | 信息', '1 個 VAC 封鎖紀錄 | 資訊', '1 ban ochrany VAC | Informace', 'VAC แบน 1 ครั้ง ในบันทึก | ข้อมูล', 'Kayıtlarda 1 VAC yasaklanması | Bilgi', '1 banimento VAC em registro | Informações', '1 banimento do VAC em registo | Informações', '1 zarejestrowana blokada VAC | Informacje', '1 bannissement VAC enregistré | Infos', '1 VAC-kielto merkitty | Tietoa', 'VAC 차단 기록 1건 | 정보', '1 feljegyzett VAC-kitiltás | Információ'])
|
122
|
+
const EMultipleVACBansOnRecord = Object.freeze(['Multiple VAC bans on record | Info', 'Πολλαπλοί αποκλεισμοί VAC στο αρχείο | Πληροφορίες', 'Meerdere vastgelegde VAC-bans | Info', 'Flere VAC-utestengelser registrert | Info', 'Adskillige VAC-udelukkelser registreret | Info', 'Mehrere VAC-Ausschlüsse | Informationen', 'Несколько блокировок VAC | Подробнее', 'Multiple banări VAC înregistrate | Informații', 'Nhiều lệnh cấm VAC được ghi nhận | Thông tin', 'Множество VAC забрани | Информация', 'Flera registrerade VAC-avstängningar | Info', 'Varios bloqueos por VAC registrados | Detalles', 'Varios bloqueos por VAC registrados | Detalles', 'Multiple VAC bans on record | Info', 'Декілька зареєстрованих блокувань VAC | Інформація', 'Più ban VAC registrati | Informazioni', '複数の VAC 検出記録 | 情報', '多个记录在案的 VAC 封禁 | 信息', '多個 VAC 封鎖紀錄 | 資訊', 'Více banů ochrany VAC | Informace', 'VAC แบนหลายครั้ง ในบันทึก | ข้อมูล', 'Kayıtlarda birden fazla VAC yasaklanması | Bilgi', 'Vários banimentos VAC em registro | Informações', 'Vários banimentos do VAC em registo | Informações', 'Wiele zarejestrowanych blokad VAC | Informacje', 'Plusieurs bannissements VAC enregistrés | Infos', 'Useita VAC-kieltoja merkitty | Tietoa', '다수의 VAC 차단 기록 | 정보', 'Több feljegyzett VAC-kitiltás | Információ'])
|
123
|
+
const E1GameBanOnRecord = Object.freeze(['1 game ban on record | Info', '1 αποκλεισμός παιχνιδιού στο αρχείο | Πληροφορίες', '1 vastgelegde spelverbanning | Info', '1 spillutestengelse registrert | Info', '1 spiludelukkelse registreret | Info', '1 Spielausschluss | Informationen', '1 игровая блокировка | Подробнее', '1 banare de joc înregistrată | Informații', '1 lệnh cấm trò chơi được ghi nhận | Thông tin', '1 игрална забрана | Информация', '1 registrerad spelavstängning | Info', '1 bloqueo en juego registrado | Detalles', '1 bloqueo en juego registrado | Detalles', '1 game ban on record | Info', '1 зареєстроване блокування у грі | Інформація', '1 ban di gioco registrato | Informazioni', '1 件のゲーム禁止記録 | 情報', '1 个记录在案的游戏封禁 | 信息', '1 個遊戲封鎖紀錄 | 資訊', '1 herní ban | Informace', 'เกมแบน 1 ครั้ง ในบันทึก | ข้อมูล', 'Kayıtlarda 1 oyun yasaklanması | Bilgi', '1 banimento de jogo em registro | Informações', '1 banimento de jogo em registo | Informações', '1 zarejestrowana blokada na grę | Informacje', '1 bannissement en jeu enregistré | Infos', '1 pelikielto merkitty | Tietoa', '게임 차단 기록 1건 | 정보', '1 feljegyzett játékkitiltás | Információ'])
|
124
|
+
const EMultipleGameBansOnRecord = Object.freeze(['Multiple game bans on record | Info', 'Πολλαπλοί αποκλεισμοί παιχνιδιών στο αρχείο | Πληροφορίες', 'Meerdere vastgelegde spelbans | Info', 'Flere spillutestengelser registrert | Info', 'Adskillige spiludelukkelser registreret | Info', 'Mehrere Spielausschlüsse | Informationen', 'Несколько игровых блокировок | Подробнее', 'Multiple banări de joc înregistrate | Informații', 'Nhiều lệnh cấm trò chơi được ghi nhận | Thông tin', 'Множество игрални забрани | Информация', 'Flera registrerade spelavstängningar | Info', 'Varios bloqueos en juegos registrados | Detalles', 'Varios bloqueos en juegos registrados | Detalles', 'Multiple game bans on record | Info', 'Декілька зареєстрованих блокувань в іграх | Інформація', 'Più ban di gioco registrati | Informazioni', '複数のゲーム禁止記録 | 情報', '多个记录在案的游戏封禁 | 信息', '多個遊戲封鎖紀錄 | 資訊', 'Více herních banů | Informace', 'เกมแบนหลายครั้ง ในบันทึก | ข้อมูล', 'Kayıtlarda birden fazla oyun yasaklanması | Bilgi', 'Vários banimentos de jogos em registro | Informações', 'Vários banimentos de jogos em registo | Informações', 'Wiele zarejestrowanych blokad na gry | Informacje', 'Plusieurs bannissements en jeu enregistrés | Infos', 'Useita pelikieltoja merkitty | Tietoa', '다수의 게임 차단 기록 | 정보', 'Több feljegyzett játékkitiltás | Információ'])
|
125
|
+
const EdaySinceLastBanRegExp = Object.freeze(['(\\d+) day\\(s\\) since last ban', '(\\d+) μέρες από τον τελευταίο αποκλεισμό', '(\\d+) dag\\(en\\) sinds vorige ban', '(\\d+) dag\\(er\\) siden siste utestengelse', '(\\d+) dag\\(e\\) siden sidste udelukkelse.', '(\\d+) Tag\\(e\\) seit dem letzten Ausschluss', 'Дней с последней блокировки: (\\d+)', '(\\d+) zi\\(le\\) de la ultima banare', '(\\d+) ngày từ lần cấm cuối', '(\\d+) ден\\(дни\\) от последна забрана', '(\\d+) dag\\(ar\\) sedan senaste avstängning', '(\\d+) día\\(s\\) desde su último bloqueo', '(\\d+) día\\(s\\) desde su último bloqueo', '(\\d+) day\\(s\\) since last ban', 'Днів з моменту останнього блокування: (\\d+)', '(\\d+) giorno/i dall\'ultimo ban', '最後の接続禁止から (\\d+) 日', '上次封禁于 (\\d+) 天前', '距離上次封鎖共 (\\d+) 天', 'Poslední ban byl uvalen před (\\d+) dny', '(\\d+) วัน นับตั้งแต่วันที่ถูกแบนครั้งล่าสุด', 'En son (\\d+) gün önce yasaklandı', '(\\d+) dia\\(s\\) desde o último banimento', '(\\d+) dia\\(s\\) desde o último ban', 'Dni od ostatniej blokady: (\\d+)', '(\\d+) jour\\(s\\) depuis le dernier bannissement', '(\\d+) päivä\\(ä\\) viime kiellosta', '마지막 차단 이후 (\\d+)일 경과', '(\\d+) nap az utolsó kitiltás óta'])
|
126
|
+
const SteamImageCDN = ['community.cloudflare.steamstatic.com', 'community.akamai.steamstatic.com'].map(cdn => `https://${cdn}`)
|
127
|
+
|
128
|
+
class SteamUser {
|
129
|
+
Steam_Language = ELanguage.english
|
130
|
+
|
131
|
+
static _EPrivacyState = Object.freeze({
|
132
|
+
Private: 1,
|
133
|
+
FriendsOnly: 2,
|
134
|
+
Public: 3
|
135
|
+
})
|
136
|
+
|
137
|
+
static _ECommentPrivacyState = Object.freeze({
|
138
|
+
Private: 2,
|
139
|
+
FriendsOnly: 0,
|
140
|
+
Public: 1
|
141
|
+
})
|
142
|
+
|
143
|
+
constructor(cookies, steamMachineAuth) {
|
144
|
+
this.setCookies(cookies, steamMachineAuth)
|
145
|
+
}
|
146
|
+
|
147
|
+
setSteamLanguage(language) {
|
148
|
+
language = language?.toLowerCase()
|
149
|
+
if(!Object.hasOwn(ELanguage, language)) {
|
150
|
+
return
|
151
|
+
}
|
152
|
+
this.Steam_Language = language
|
153
|
+
this._cookies = SteamUser.generateCookie({
|
154
|
+
...SteamUser.parseCookie(this._cookies),
|
155
|
+
Steam_Language: this.Steam_Language,
|
156
|
+
})
|
157
|
+
}
|
158
|
+
|
159
|
+
setCookies(cookies, _steamMachineAuth) {
|
160
|
+
if(!cookies) {
|
161
|
+
return
|
162
|
+
}
|
163
|
+
cookies = Array.isArray(cookies) ? cookies.join(';') : cookies
|
164
|
+
|
165
|
+
let {
|
166
|
+
steamMachineAuth,
|
167
|
+
steamLoginSecure,
|
168
|
+
steamRememberLogin,
|
169
|
+
steamID,
|
170
|
+
miniprofile,
|
171
|
+
sessionid,
|
172
|
+
} = SteamUser.parseCookie(cookies)
|
173
|
+
|
174
|
+
if(!steamMachineAuth && _steamMachineAuth) {
|
175
|
+
steamMachineAuth = _steamMachineAuth
|
176
|
+
}
|
177
|
+
if(!sessionid) {
|
178
|
+
sessionid = SteamUser.generateSessionID()
|
179
|
+
}
|
180
|
+
|
181
|
+
this._cookies = SteamUser.generateCookie({
|
182
|
+
steamMachineAuth,
|
183
|
+
steamLoginSecure,
|
184
|
+
steamRememberLogin,
|
185
|
+
steamID,
|
186
|
+
miniprofile,
|
187
|
+
sessionid,
|
188
|
+
Steam_Language: this.Steam_Language,
|
189
|
+
})
|
190
|
+
|
191
|
+
this._sessionid = sessionid
|
192
|
+
this._steamid_user = steamID
|
193
|
+
this._miniprofile_user = miniprofile
|
194
|
+
this._steamMachineAuth = steamMachineAuth
|
195
|
+
this._steamLoginSecure = steamLoginSecure
|
196
|
+
this._steamRememberLogin = steamRememberLogin
|
197
|
+
}
|
198
|
+
|
199
|
+
static parseCookie(cookies) {
|
200
|
+
if(!Array.isArray(cookies)) {
|
201
|
+
cookies = cookies.split(';')
|
202
|
+
}
|
203
|
+
cookies = cookies.map(c => decodeURIComponent(c.trim()))
|
204
|
+
|
205
|
+
|
206
|
+
const sessionid = cookies.find(c => c.startsWith('sessionid'))?.substringAfter('=')
|
207
|
+
const Steam_Language = cookies.find(c => c.startsWith('Steam_Language'))?.substringAfter('=')
|
208
|
+
|
209
|
+
let steamID = cookies.find(c => c.startsWith('steamRememberLogin='))?.substringBetween('=', '||')
|
210
|
+
if(!steamID) {
|
211
|
+
//multiple steamMachineAuth for multiple steamID
|
212
|
+
//steamID = cookies.find(c => c.startsWith('steamMachineAuth'))?.substringBetween('steamMachineAuth', '=')
|
213
|
+
if(!steamID) {
|
214
|
+
steamID = cookies.find(c => c.startsWith('steamLoginSecure='))?.substringBetween('=', '||')
|
215
|
+
}
|
216
|
+
}
|
217
|
+
const miniprofile = SteamUser.steamID642Miniprofile(steamID)
|
218
|
+
const steamMachineAuth = cookies.find(c => c.startsWith('steamMachineAuth' + steamID))?.substringAfter('=')
|
219
|
+
const steamLoginSecure = cookies.find(c => c.startsWith('steamLoginSecure'))?.substringAfter('||')
|
220
|
+
const steamRememberLogin = cookies.find(c => c.startsWith('steamRememberLogin'))?.substringAfter('||')
|
221
|
+
|
222
|
+
return {
|
223
|
+
steamMachineAuth,
|
224
|
+
steamLoginSecure,
|
225
|
+
steamRememberLogin,
|
226
|
+
steamID,
|
227
|
+
miniprofile,
|
228
|
+
sessionid,
|
229
|
+
Steam_Language,
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
static generateCookie({
|
234
|
+
steamMachineAuth,
|
235
|
+
steamLoginSecure,
|
236
|
+
steamRememberLogin,
|
237
|
+
steamID,
|
238
|
+
sessionid,
|
239
|
+
Steam_Language,
|
240
|
+
}) {
|
241
|
+
return [steamLoginSecure && `steamLoginSecure=${steamID}||${steamLoginSecure}`, steamMachineAuth && `steamMachineAuth${steamID}=${steamMachineAuth}`, steamRememberLogin !== undefined ? `steamRememberLogin=${steamID}||${steamRememberLogin}` : steamRememberLogin, sessionid && `sessionid=${sessionid}`, Steam_Language && `Steam_Language=${Steam_Language}`,].filter(Boolean).join(';')
|
242
|
+
}
|
243
|
+
|
244
|
+
getCookies() {
|
245
|
+
return this._cookies
|
246
|
+
}
|
247
|
+
|
248
|
+
getSteamidUser() {
|
249
|
+
return this._steamid_user
|
250
|
+
}
|
251
|
+
|
252
|
+
|
253
|
+
getSessionid() {
|
254
|
+
return this._sessionid
|
255
|
+
}
|
256
|
+
|
257
|
+
getSteamMachineAuth() {
|
258
|
+
return this._steamMachineAuth
|
259
|
+
}
|
260
|
+
|
261
|
+
getSteamUserProfileURL(steamID = this.getSteamidUser()) {
|
262
|
+
return `profiles/${steamID}`
|
263
|
+
}
|
264
|
+
|
265
|
+
getMySteamUserProfileURL() {
|
266
|
+
return this.getSteamUserProfileURL()
|
267
|
+
}
|
268
|
+
|
269
|
+
/**
|
270
|
+
*
|
271
|
+
* start static functions
|
272
|
+
*
|
273
|
+
* */
|
274
|
+
|
275
|
+
|
276
|
+
async getUserSummary(steamID = this.getSteamidUser(), parts = []) {
|
277
|
+
return await SteamUser.getUserSummary(steamID, parts, this.getCookies())
|
278
|
+
}
|
279
|
+
|
280
|
+
static async getUserSummary(steamID, parts = [], cookie = null) {
|
281
|
+
const xmlMap = {
|
282
|
+
name: null,
|
283
|
+
realname: null,
|
284
|
+
steamID: null,
|
285
|
+
onlineState: null,
|
286
|
+
|
287
|
+
stateMessageFull: null,
|
288
|
+
stateMessage: null,
|
289
|
+
stateMessageGame: null,
|
290
|
+
stateMessage_NonSteamGame: null,
|
291
|
+
|
292
|
+
privacyState: null,
|
293
|
+
visibilityState: null,
|
294
|
+
avatarHash: null,
|
295
|
+
vacBanned: null,
|
296
|
+
tradeBanState: null,
|
297
|
+
isLimitedAccount: null,
|
298
|
+
customURL: null,
|
299
|
+
memberSince: null,
|
300
|
+
steamRating: null,
|
301
|
+
location: null,
|
302
|
+
summary: null,
|
303
|
+
privacyMessage: null,
|
304
|
+
notYetSetup: null,
|
305
|
+
}
|
306
|
+
|
307
|
+
const profileMap = {
|
308
|
+
name: null,
|
309
|
+
realname: null,
|
310
|
+
steamID: null,
|
311
|
+
avatarHash: null,
|
312
|
+
avatarFrame: null,
|
313
|
+
customURL: null,
|
314
|
+
location: null,
|
315
|
+
summary: null,
|
316
|
+
notYetSetup: null,
|
317
|
+
profile_private_info: null,
|
318
|
+
lobbyLink: null,
|
319
|
+
addFriendEnable: null,
|
320
|
+
isPrivate: null,
|
321
|
+
url: null,
|
322
|
+
nickname: null,
|
323
|
+
level: null,
|
324
|
+
dayLastBan: null,
|
325
|
+
gameBanFull: null,
|
326
|
+
isVACBan: null,
|
327
|
+
isGameBan: null,
|
328
|
+
isTradeBan: null,
|
329
|
+
daysSinceLastBan: null,
|
330
|
+
}
|
331
|
+
|
332
|
+
const mustFetchFromURL = parts.length === 0 || parts.some(key => !Object.hasOwn(xmlMap, key))//because xml not have some parts
|
333
|
+
let mustFetchFromXML = parts.length === 0 || parts.some(key => !Object.hasOwn(profileMap, key))//because profile not have some parts
|
334
|
+
|
335
|
+
if(!mustFetchFromURL && !mustFetchFromXML) {
|
336
|
+
mustFetchFromXML = true
|
337
|
+
}
|
338
|
+
|
339
|
+
const queue = []
|
340
|
+
if(mustFetchFromURL) {
|
341
|
+
queue.push((async function () {
|
342
|
+
try {
|
343
|
+
const result = (await request({
|
344
|
+
url: 'https://steamcommunity.com/profiles/' + steamID,
|
345
|
+
headers: {...cookie && {cookie}},
|
346
|
+
})).data
|
347
|
+
return SteamUser._parseUserProfile(result) || 'Error'
|
348
|
+
} catch (e) {
|
349
|
+
}
|
350
|
+
})())
|
351
|
+
}
|
352
|
+
if(mustFetchFromXML) {
|
353
|
+
queue.push((async function () {
|
354
|
+
try {
|
355
|
+
const resultXml = await SteamUser._httpRequestXML(`https://steamcommunity.com/profiles/${steamID}/?xml=1`)
|
356
|
+
return await SteamUser._parseSummaryFromXML(resultXml)
|
357
|
+
} catch (e) {
|
358
|
+
}
|
359
|
+
})())
|
360
|
+
}
|
361
|
+
|
362
|
+
const results = await Promise.all(queue)
|
363
|
+
return results.reduce(function (previousValue, currentValue) {
|
364
|
+
if(previousValue === 'Invalid' || currentValue === 'Invalid') {
|
365
|
+
return 'Invalid'
|
366
|
+
}
|
367
|
+
if(previousValue === 'Error' || currentValue === 'Error') {
|
368
|
+
return 'Error'
|
369
|
+
}
|
370
|
+
|
371
|
+
//order : undefined, null, '', Boolean
|
372
|
+
for (const key in currentValue) {
|
373
|
+
let previousValueOrder = 0
|
374
|
+
if(previousValue[key] === undefined) {
|
375
|
+
previousValueOrder = 0
|
376
|
+
}
|
377
|
+
else if(previousValue[key] === null) {
|
378
|
+
previousValueOrder = 1
|
379
|
+
}
|
380
|
+
else if(previousValue[key] === '') {
|
381
|
+
previousValueOrder = 2
|
382
|
+
}
|
383
|
+
else {
|
384
|
+
previousValueOrder = 3
|
385
|
+
}
|
386
|
+
|
387
|
+
let currentValueOrder = 0
|
388
|
+
if(currentValue[key] === undefined) {
|
389
|
+
currentValueOrder = 0
|
390
|
+
}
|
391
|
+
else if(currentValue[key] === null) {
|
392
|
+
currentValueOrder = 1
|
393
|
+
}
|
394
|
+
else if(currentValue[key] === '') {
|
395
|
+
currentValueOrder = 2
|
396
|
+
}
|
397
|
+
else {
|
398
|
+
currentValueOrder = 3
|
399
|
+
}
|
400
|
+
|
401
|
+
if(currentValueOrder > previousValueOrder) {
|
402
|
+
previousValue[key] = currentValue[key]
|
403
|
+
}
|
404
|
+
}
|
405
|
+
|
406
|
+
return previousValue
|
407
|
+
}, {})
|
408
|
+
}
|
409
|
+
|
410
|
+
static async getUserSummaryFromXML(steamID) {
|
411
|
+
const resultXml = await SteamUser._httpRequestXML(`https://steamcommunity.com/profiles/${steamID}/?xml=1`)
|
412
|
+
return await SteamUser._parseSummaryFromXML(resultXml)
|
413
|
+
}
|
414
|
+
|
415
|
+
static async _parseSummaryFromXML(resultXml) {
|
416
|
+
if(!resultXml) {
|
417
|
+
return
|
418
|
+
}
|
419
|
+
|
420
|
+
let json
|
421
|
+
try {
|
422
|
+
json = await xml2js.parseStringPromise(resultXml)
|
423
|
+
} catch (e) {
|
424
|
+
// console.error(e)
|
425
|
+
return
|
426
|
+
}
|
427
|
+
|
428
|
+
if(json?.response?.error?.[0] === 'The specified profile could not be found.') {
|
429
|
+
return 'Invalid'
|
430
|
+
}
|
431
|
+
|
432
|
+
if(!json?.profile) {
|
433
|
+
return
|
434
|
+
}
|
435
|
+
for (let key in json.profile) {
|
436
|
+
if(Array.isArray(json.profile[key]) && json.profile[key].length === 1) {
|
437
|
+
json.profile[key] = json.profile[key][0]
|
438
|
+
}
|
439
|
+
}
|
440
|
+
|
441
|
+
const _profile = json.profile
|
442
|
+
if(!_profile) {
|
443
|
+
return
|
444
|
+
}
|
445
|
+
|
446
|
+
|
447
|
+
let memberSince
|
448
|
+
if((memberSince = moment.utc(`November 3, 2016`, ['MMMM DD, YYYY', 'MMMM D, YYYY', 'MMMM DD', 'MMMM D'], true)).isValid()) {
|
449
|
+
memberSince = memberSince.valueOf()
|
450
|
+
}
|
451
|
+
else {
|
452
|
+
memberSince = _profile.memberSince
|
453
|
+
}
|
454
|
+
|
455
|
+
const avatarHash = SteamUser.GetAvatarHashFromMultipleURL([_profile.avatarIcon, _profile.avatarFull])
|
456
|
+
const privacyMessage = _profile.privacyMessage?._
|
457
|
+
|
458
|
+
//parse stateMessage
|
459
|
+
let stateMessage = '',
|
460
|
+
stateMessageGame = '',
|
461
|
+
stateMessage_NonSteamGame = ''
|
462
|
+
if(!_profile.stateMessage) {
|
463
|
+
}
|
464
|
+
else if(['Online', 'Online using Big Picture', 'Online using VR'].includes(_profile.stateMessage)) {
|
465
|
+
stateMessage = 'online'
|
466
|
+
_profile.stateMessage = ''
|
467
|
+
}
|
468
|
+
else if(_profile.stateMessage === 'Offline') {
|
469
|
+
stateMessage = 'offline'
|
470
|
+
_profile.stateMessage = ''
|
471
|
+
}
|
472
|
+
else if(_profile.stateMessage.startsWith('In non-Steam game<br/>')) {
|
473
|
+
stateMessage = 'in-game'
|
474
|
+
stateMessage_NonSteamGame = _profile.stateMessage.substringAfter('<br/>')
|
475
|
+
_profile.stateMessage = ''
|
476
|
+
}
|
477
|
+
else if(_profile.stateMessage.startsWith('In-Game<br/>')) {
|
478
|
+
stateMessage = 'in-game'
|
479
|
+
stateMessageGame = _profile.stateMessage.substringAfter('<br/>')
|
480
|
+
_profile.stateMessage = ''
|
481
|
+
}
|
482
|
+
else {
|
483
|
+
//error
|
484
|
+
}
|
485
|
+
|
486
|
+
|
487
|
+
return {
|
488
|
+
name: _profile.steamID,
|
489
|
+
realname: _profile.realname || '',
|
490
|
+
steamID: _profile.steamID64,
|
491
|
+
onlineState: _profile.onlineState,//offline in-game online
|
492
|
+
|
493
|
+
stateMessageFull: _profile.stateMessage,// 'Offline' Online In-Game<br/>16bit Trader In non-Steam game<br/>
|
494
|
+
stateMessage,
|
495
|
+
stateMessageGame,
|
496
|
+
stateMessage_NonSteamGame,
|
497
|
+
|
498
|
+
privacyState: _profile.privacyState,// 'public', private
|
499
|
+
visibilityState: !isNaN(parseInt(_profile.visibilityState)) ? parseInt(_profile.visibilityState) : undefined,//1, 2, 3
|
500
|
+
avatarHash,
|
501
|
+
vacBanned: !isNaN(parseInt(_profile.vacBanned)) ? parseInt(_profile.vacBanned) : undefined,//0, 1, 2
|
502
|
+
tradeBanState: _profile.tradeBanState,//'None'
|
503
|
+
isLimitedAccount: !isNaN(parseInt(_profile.isLimitedAccount)) ? parseInt(_profile.isLimitedAccount) : undefined,//0 or 1
|
504
|
+
customURL: _profile.customURL,
|
505
|
+
memberSince,//'August 19, 2018', April 24, September 6, 2019
|
506
|
+
steamRating: _profile.steamRating,
|
507
|
+
location: _profile.location,
|
508
|
+
summary: SteamUser._formatSummary(_profile.summary),
|
509
|
+
privacyMessage: NotYetSetupProfileTextList.includes(privacyMessage) ? '___NotYetSetupProfile___' : privacyMessage,//'This user has not yet set up their Steam Community profile.If you know this person, encourage them to set up their profile and join in the gaming!'
|
510
|
+
notYetSetup: NotYetSetupProfileTextList.includes(privacyMessage),
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
async getUserSummaryFromProfile(steamID = this.getSteamidUser()) {
|
515
|
+
return await SteamUser.getUserSummaryFromProfile(steamID, this.getCookies())
|
516
|
+
}
|
517
|
+
|
518
|
+
static async getUserSummaryFromProfile(steamID, cookie) {
|
519
|
+
const result = (await request({
|
520
|
+
url: 'https://steamcommunity.com/profiles/' + steamID,
|
521
|
+
headers: {...cookie && {cookie}},
|
522
|
+
}))?.data
|
523
|
+
return SteamUser._parseUserProfile(result)
|
524
|
+
}
|
525
|
+
|
526
|
+
static _formatSummary(summary) {
|
527
|
+
summary = summary || ''
|
528
|
+
for (let i = 1; i < SteamImageCDN.length; i++) {
|
529
|
+
summary = summary.replaceAll(SteamImageCDN[i], SteamImageCDN[0])
|
530
|
+
}
|
531
|
+
return EmptyProfileSummary.includes(summary) ? null : summary
|
532
|
+
}
|
533
|
+
|
534
|
+
static _parseUserProfile(html) {
|
535
|
+
if(!html) {
|
536
|
+
return
|
537
|
+
}
|
538
|
+
const $ = cheerio.load(html)
|
539
|
+
|
540
|
+
const sectionText = $('#message .sectionText').text()?.trim()
|
541
|
+
if(ErrorProcessingRequest.includes(sectionText)) {
|
542
|
+
return
|
543
|
+
}
|
544
|
+
const profile_private_info = $('.profile_header_summary .profile_private_info').text()?.trim()
|
545
|
+
const addFriendEnable = !!$('#btn_add_friend').length
|
546
|
+
const name = $('.persona_name .actual_persona_name').text().trim()
|
547
|
+
const $personaLevel = $('.persona_level .friendPlayerLevelNum')
|
548
|
+
const level = $personaLevel.length ? parseInt($personaLevel.text()) : null
|
549
|
+
|
550
|
+
const g_rgProfileDataExample = {
|
551
|
+
url: 'https://steamcommunity.com/id/natri99/',
|
552
|
+
steamid: '76561199040402348',
|
553
|
+
personaname: 'Natri',
|
554
|
+
summary: 'Sub: <a class="bb_link" href="https://steamcommunity.com/id/Natri2099/" target="_blank" rel="noreferrer" >https://steamcommunity.com/id/Natri2099/</a> '
|
555
|
+
}
|
556
|
+
const g_rgProfileData = JSON_parse(html.substringBetweenOrNull('g_rgProfileData = ', '"};') + '"}')
|
557
|
+
if(!g_rgProfileData) {
|
558
|
+
return
|
559
|
+
}
|
560
|
+
|
561
|
+
const lobbyLink = $(`.profile_in_game_joingame a[href*='steam://joinlobby/']`).attr('href')
|
562
|
+
const nickname = $('.persona_name .nickname').text()
|
563
|
+
|
564
|
+
const profileBanStatusEl = $('.profile_ban_status').clone()
|
565
|
+
|
566
|
+
const gameBanFull = [...($(profileBanStatusEl.children()))]
|
567
|
+
.map(line => {
|
568
|
+
const text = $(line).text()
|
569
|
+
$(line).remove()
|
570
|
+
return text
|
571
|
+
}).concat(profileBanStatusEl.text()).map(text => text?.replaceAll(/[\t\n\r]/gi, ' ')?.replaceAll(/\s+/gi, ' ')?.trim()).filter(Boolean)
|
572
|
+
const GameBan = SteamUser.parseGameBanType(gameBanFull)
|
573
|
+
let dayLastBan = null
|
574
|
+
if(GameBan && GameBan.daysSinceLastBan !== null) {
|
575
|
+
dayLastBan = moment()
|
576
|
+
.startOf('day')
|
577
|
+
.subtract(GameBan.daysSinceLastBan, 'days')
|
578
|
+
.valueOf()
|
579
|
+
}
|
580
|
+
|
581
|
+
const url = g_rgProfileData.url ? (g_rgProfileData.url.endsWith('/') ? g_rgProfileData.url.substringBeforeLast('/') : g_rgProfileData.url) : ''
|
582
|
+
const customURL = SteamUser.getCustomURL_from_ProfileURL(url) || ''
|
583
|
+
|
584
|
+
const avatarFrameEl = $('.profile_header .playerAvatar .profile_avatar_frame')
|
585
|
+
const avatarFrame = avatarFrameEl.find('img').attr('src')
|
586
|
+
avatarFrameEl.remove()
|
587
|
+
|
588
|
+
// const avatarFull = $(`.profile_header .playerAvatar img`).attr('src')
|
589
|
+
const avatarFulls = [$(`head > link[rel="image_src"][href$="_full.jpg"]`).attr('href'), $(`head > meta[name="twitter:image"][content$="_full.jpg"]`).attr('content'), $(`head > meta[property="og:image"][content$="_full.jpg"]`).attr('content'), $(`.profile_header .playerAvatar img`).attr('src'),].filter(Boolean)
|
590
|
+
const avatarHash = SteamUser.GetAvatarHashFromMultipleURL(avatarFulls)
|
591
|
+
const location = $('img.profile_flag').attr('src')?.substringBetweenOrNull('/images/countryflags/', '.')?.toUpperCase() || ''
|
592
|
+
|
593
|
+
const playerAvatarClass = $('.profile_header .playerAvatar').attr('class')
|
594
|
+
const onlineState = ['online', 'offline', 'in-game'].find(_onlineState => playerAvatarClass.includes(_onlineState))
|
595
|
+
const gamename = $('.profile_in_game .profile_in_game_name').text()?.trim() || ''
|
596
|
+
let stateMessageGame = ''
|
597
|
+
if(onlineState === 'in-game') {
|
598
|
+
stateMessageGame = gamename
|
599
|
+
}
|
600
|
+
|
601
|
+
return {
|
602
|
+
name: g_rgProfileData.personaname,
|
603
|
+
realname: $('.header_real_name bdi').text()?.trim() || '',
|
604
|
+
onlineState,
|
605
|
+
steamID: g_rgProfileData.steamid,
|
606
|
+
avatarHash,
|
607
|
+
avatarFrame,
|
608
|
+
customURL,
|
609
|
+
location,
|
610
|
+
summary: SteamUser._formatSummary(g_rgProfileData.summary),
|
611
|
+
notYetSetup: NotYetSetupProfileTextList.includes(profile_private_info),
|
612
|
+
profile_private_info: profile_private_info ? ((NotYetSetupProfileTextList.includes(profile_private_info) ? '___NotYetSetupProfile___' : (PrivateProfileTextList.includes(profile_private_info) ? '___PrivateProfile___' : profile_private_info))) : null,
|
613
|
+
lobbyLink,
|
614
|
+
addFriendEnable,
|
615
|
+
isPrivate: PrivateProfileTextList.includes(profile_private_info),
|
616
|
+
url,
|
617
|
+
nickname,
|
618
|
+
level,
|
619
|
+
dayLastBan,
|
620
|
+
gameBanFull: gameBanFull.length ? gameBanFull : null,
|
621
|
+
isVACBan: GameBan?.isVACBan,
|
622
|
+
isGameBan: GameBan?.isGameBan,
|
623
|
+
isTradeBan: GameBan?.isTradeBan,
|
624
|
+
daysSinceLastBan: GameBan?.daysSinceLastBan,
|
625
|
+
stateMessageGame,
|
626
|
+
sectionText,
|
627
|
+
}
|
628
|
+
}
|
629
|
+
|
630
|
+
static async QueryLocations() {
|
631
|
+
let response = await request(`https://steamcommunity.com//actions/QueryLocations/`)
|
632
|
+
return response?.data || []
|
633
|
+
const resultExample = [{
|
634
|
+
countrycode: 'US',
|
635
|
+
hasstates: 1,
|
636
|
+
countryname: 'United States'
|
637
|
+
}, {
|
638
|
+
countrycode: 'CA',
|
639
|
+
hasstates: 1,
|
640
|
+
countryname: 'Canada'
|
641
|
+
}]
|
642
|
+
}
|
643
|
+
|
644
|
+
static async queryAppList(term) {
|
645
|
+
let response = await request(`https://store.steampowered.com/search/results/?query&start=0&count=50&dynamic_data=&sort_by=_ASC&term=${encodeURIComponent(term)}&infinite=1`)
|
646
|
+
if(!response?.data?.results_html) {
|
647
|
+
return []
|
648
|
+
}
|
649
|
+
const $ = cheerio.load(response
|
650
|
+
?.data
|
651
|
+
?.results_html
|
652
|
+
?.replaceAll(/[\t\n\r]/gi, '')
|
653
|
+
.trim())
|
654
|
+
const results = []
|
655
|
+
$(`a.search_result_row`).each(function () {
|
656
|
+
const el = $(this)
|
657
|
+
const appid = parseInt(el.attr('data-ds-appid'))
|
658
|
+
const name = el.find('.search_name .title').text().trim()
|
659
|
+
const img = el.find('.search_capsule img').attr('src').trim()
|
660
|
+
const price = el.find('.search_price').text().trim()
|
661
|
+
results.push({
|
662
|
+
appid,
|
663
|
+
name,
|
664
|
+
img,
|
665
|
+
price,
|
666
|
+
})
|
667
|
+
})
|
668
|
+
return results
|
669
|
+
|
670
|
+
}
|
671
|
+
|
672
|
+
static async suggestAppList(term) {
|
673
|
+
let response = await request(`https://store.steampowered.com/search/suggest?term=${encodeURIComponent(term)}&f=games&cc=VN&realm=1&l=english&excluded_content_descriptors%5B%5D=3&excluded_content_descriptors%5B%5D=4&use_store_query=1`)
|
674
|
+
if(!response?.data) {
|
675
|
+
return []
|
676
|
+
}
|
677
|
+
const $ = response._$()
|
678
|
+
const results = []
|
679
|
+
$(`a.match`).each(function () {
|
680
|
+
const el = $(this)
|
681
|
+
const appid = parseInt(el.attr('data-ds-appid'))
|
682
|
+
const name = el.find('.match_name').text().trim()
|
683
|
+
const img = el.find('.match_img img').attr('src').trim()
|
684
|
+
const price = el.find('.match_price').text().trim()
|
685
|
+
results.push({
|
686
|
+
appid,
|
687
|
+
name,
|
688
|
+
img,
|
689
|
+
price,
|
690
|
+
})
|
691
|
+
})
|
692
|
+
return results
|
693
|
+
}
|
694
|
+
|
695
|
+
static steamID642Miniprofile(steamID) {
|
696
|
+
return parseInt((new SteamID(steamID)).getSteam3RenderedID().split(':').pop().split(']')[0])
|
697
|
+
}
|
698
|
+
|
699
|
+
static miniprofile2SteamID64(miniprofile) {
|
700
|
+
const accountid = parseInt(miniprofile)
|
701
|
+
if(isNaN(accountid)) {
|
702
|
+
//debug
|
703
|
+
console_log('debug')
|
704
|
+
return
|
705
|
+
}
|
706
|
+
return (SteamID.fromIndividualAccountID(accountid)).getSteamID64()
|
707
|
+
}
|
708
|
+
|
709
|
+
static groupminiid2SteamID64(miniid) {
|
710
|
+
const accountid = parseInt(miniid)
|
711
|
+
if(isNaN(accountid)) {
|
712
|
+
//debug
|
713
|
+
console_log('debug')
|
714
|
+
return
|
715
|
+
}
|
716
|
+
|
717
|
+
const sid = new SteamID()
|
718
|
+
sid.accountid = accountid
|
719
|
+
sid.type = SteamID.Type.CLAN
|
720
|
+
sid.instance = SteamID.Instance.ALL
|
721
|
+
sid.universe = SteamID.Universe.PUBLIC
|
722
|
+
|
723
|
+
return sid.getSteamID64()
|
724
|
+
}
|
725
|
+
|
726
|
+
static getCustomURL_from_ProfileURL(profileURL) {
|
727
|
+
const split = 'steamcommunity.com/id/'
|
728
|
+
if(profileURL.includes(split)) {
|
729
|
+
const customURL = profileURL.substringAfter(split)
|
730
|
+
return customURL.includes('/') ? customURL.substringBefore('/') : customURL
|
731
|
+
}
|
732
|
+
return null
|
733
|
+
}
|
734
|
+
|
735
|
+
static getProfileURL_from_CustomURL(customURL) {
|
736
|
+
if(typeof customURL !== 'string' || !customURL) {
|
737
|
+
return null
|
738
|
+
}
|
739
|
+
return `https://steamcommunity.com/id/${customURL.trim()}`
|
740
|
+
}
|
741
|
+
|
742
|
+
static async GetAppList() {
|
743
|
+
let result = await request(`http://api.steampowered.com/ISteamApps/GetAppList/v0002/?format=json`)
|
744
|
+
return result?.data
|
745
|
+
const resultExample = {
|
746
|
+
applist: {
|
747
|
+
apps: [{
|
748
|
+
appid: 1829051,
|
749
|
+
name: 'XXXXX'
|
750
|
+
},]
|
751
|
+
}
|
752
|
+
}
|
753
|
+
}
|
754
|
+
|
755
|
+
static async GetCurrentVersion(appID) {
|
756
|
+
let result = await request(`https://api.steampowered.com/ISteamApps/UpToDateCheck/v1/?format=json&appid=${appID}&version=0`)
|
757
|
+
return result?.data?.response?.required_version
|
758
|
+
}
|
759
|
+
|
760
|
+
static generateSessionID() {
|
761
|
+
return randomBytes(12).toString('hex')
|
762
|
+
}
|
763
|
+
|
764
|
+
static async communityLogin({
|
765
|
+
username,
|
766
|
+
password,
|
767
|
+
emailauth,
|
768
|
+
cookie,
|
769
|
+
steamMachineAuth
|
770
|
+
}) {
|
771
|
+
if(!username || !password) {
|
772
|
+
return
|
773
|
+
}
|
774
|
+
username = username?.toLowerCase()
|
775
|
+
const rsakey = await this.getrsakey(username)
|
776
|
+
if(!rsakey || !rsakey.success) {
|
777
|
+
return
|
778
|
+
}
|
779
|
+
|
780
|
+
const key = new RSA()
|
781
|
+
key.setPublic(rsakey.publickey_mod, rsakey.publickey_exp)
|
782
|
+
const encryptedPassword = hex2b64(key.encrypt(password))
|
783
|
+
|
784
|
+
if(cookie) {
|
785
|
+
const cookieParts = SteamUser.parseCookie(cookie)
|
786
|
+
if(!cookieParts.steamMachineAuth && steamMachineAuth) {
|
787
|
+
cookieParts.steamMachineAuth = steamMachineAuth
|
788
|
+
}
|
789
|
+
cookie = SteamUser.generateCookie(cookieParts)
|
790
|
+
}
|
791
|
+
|
792
|
+
|
793
|
+
const postData = {
|
794
|
+
captcha_text: '',
|
795
|
+
captchagid: -1,
|
796
|
+
emailauth: emailauth,
|
797
|
+
emailsteamid: '',
|
798
|
+
password: encryptedPassword,
|
799
|
+
remember_login: 'true',
|
800
|
+
rsatimestamp: rsakey.timestamp,
|
801
|
+
twofactorcode: '',
|
802
|
+
username,
|
803
|
+
loginfriendlyname: 'Playerhubs.com',
|
804
|
+
donotcache: Date.now(),
|
805
|
+
tokentype: -1,
|
806
|
+
}
|
807
|
+
|
808
|
+
let result = await request({
|
809
|
+
url: `https://steamcommunity.com/login/dologin/`,
|
810
|
+
method: 'POST',
|
811
|
+
headers: {
|
812
|
+
Connection: 'keep-alive',
|
813
|
+
accept: '*/*',
|
814
|
+
'accept-language': 'en-US,en;q=0.9',
|
815
|
+
'cache-control': 'no-cache',
|
816
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
817
|
+
pragma: 'no-cache',
|
818
|
+
'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"',
|
819
|
+
'sec-ch-ua-mobile': '?0',
|
820
|
+
'sec-ch-ua-platform': '"Windows"',
|
821
|
+
'sec-fetch-dest': 'empty',
|
822
|
+
'sec-fetch-mode': 'cors',
|
823
|
+
'sec-fetch-site': 'same-origin',
|
824
|
+
'x-kl-ajax-request': 'Ajax_Request',
|
825
|
+
'x-requested-with': 'XMLHttpRequest',
|
826
|
+
Referer: 'https://steamcommunity.com/login/home/',
|
827
|
+
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
828
|
+
Cookie: cookie || rsakey.cookie.join(';'),
|
829
|
+
},
|
830
|
+
data: Object.keys(postData).map(function (key) {
|
831
|
+
let value = postData[key]
|
832
|
+
if(typeof value === 'undefined') {
|
833
|
+
value = ''
|
834
|
+
}
|
835
|
+
return `${key}=${encodeURIComponent(value.toString())}`
|
836
|
+
}).join('&'),
|
837
|
+
})
|
838
|
+
|
839
|
+
if(result?.data) {
|
840
|
+
const jsonResponse = {
|
841
|
+
...result.data,
|
842
|
+
timestamp: moment().unix()
|
843
|
+
}
|
844
|
+
if(jsonResponse.success) {
|
845
|
+
const resultExample = {
|
846
|
+
success: true,
|
847
|
+
requires_twofactor: false,
|
848
|
+
login_complete: true,
|
849
|
+
transfer_urls: ['https://store.steampowered.com/login/transfer', 'https://help.steampowered.com/login/transfer'],
|
850
|
+
transfer_parameters: {
|
851
|
+
steamid: '76561199277189971',
|
852
|
+
token_secure: 'AE985344A09FABA46E8095E1AD6B49AC0B64C8FA',
|
853
|
+
auth: 'be54a809d47fe7d61082c806474b9583',
|
854
|
+
remember_login: true,
|
855
|
+
webcookie: '323B473A2023BE5868F2445AF41D814283A7CD7E'
|
856
|
+
}
|
857
|
+
}
|
858
|
+
let cookies = result.headers['set-cookie']?.map(c => decodeURI(c.substringBefore(';')).trim()) //array
|
859
|
+
let expires
|
860
|
+
try {
|
861
|
+
expires = result.headers['set-cookie'].find(c => c.toLowerCase().startsWith('steamRememberLogin'.toLowerCase())).split(';').map(k => k.trim()).find(k => k.toLowerCase().startsWith('Expires='.toLowerCase())).substringAfter('Expires=')
|
862
|
+
} catch (e) {
|
863
|
+
}
|
864
|
+
|
865
|
+
if(!cookies.some(c => c.startsWith('sessionid='))) {
|
866
|
+
const sessionid = SteamUser.generateSessionID()
|
867
|
+
cookies.push(`sessionid=${sessionid}`)
|
868
|
+
}
|
869
|
+
|
870
|
+
return {
|
871
|
+
...jsonResponse,
|
872
|
+
expiresStr: expires,
|
873
|
+
expires: expires ? moment(expires).valueOf() : null,
|
874
|
+
cookie: cookies.join(';')
|
875
|
+
}
|
876
|
+
}
|
877
|
+
else {
|
878
|
+
if(jsonResponse.emailauth_needed) {
|
879
|
+
const resultExample = {
|
880
|
+
success: false,
|
881
|
+
requires_twofactor: false,
|
882
|
+
message: '',
|
883
|
+
emailauth_needed: true,
|
884
|
+
emaildomain: 'gmail.com',
|
885
|
+
emailsteamid: '76561199277189971'
|
886
|
+
}
|
887
|
+
}
|
888
|
+
else if(jsonResponse.message) {
|
889
|
+
const resultExample = {
|
890
|
+
success: false,
|
891
|
+
requires_twofactor: false,
|
892
|
+
message: 'There have been too many login failures from your network in a short time period. Please wait and try again later.',
|
893
|
+
captcha_needed: false,
|
894
|
+
captcha_gid: -1
|
895
|
+
}
|
896
|
+
}
|
897
|
+
|
898
|
+
return jsonResponse
|
899
|
+
}
|
900
|
+
}
|
901
|
+
|
902
|
+
/*if (result.statusText === "Unauthorized") {
|
903
|
+
console_log(result.statusText);
|
904
|
+
} else {
|
905
|
+
console_log(result.data);
|
906
|
+
}*/
|
907
|
+
// return result
|
908
|
+
}
|
909
|
+
|
910
|
+
static async getrsakey(username) {
|
911
|
+
if(!username) {
|
912
|
+
return
|
913
|
+
}
|
914
|
+
username = username?.toLowerCase()
|
915
|
+
let response = await request({
|
916
|
+
url: `https://steamcommunity.com/login/getrsakey/`,
|
917
|
+
method: 'POST',
|
918
|
+
headers: {
|
919
|
+
accept: '*/*',
|
920
|
+
'accept-language': 'en-US,en;q=0.9',
|
921
|
+
'cache-control': 'no-cache',
|
922
|
+
'content-type': 'multipart/form-data',
|
923
|
+
pragma: 'no-cache',
|
924
|
+
'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"',
|
925
|
+
'sec-ch-ua-mobile': '?0',
|
926
|
+
'sec-ch-ua-platform': '"Windows"',
|
927
|
+
'sec-fetch-dest': 'empty',
|
928
|
+
'sec-fetch-mode': 'cors',
|
929
|
+
'sec-fetch-site': 'same-origin',
|
930
|
+
'x-kl-ajax-request': 'Ajax_Request',
|
931
|
+
'x-requested-with': 'XMLHttpRequest',
|
932
|
+
Referer: 'https://steamcommunity.com/login/home/',
|
933
|
+
'Referrer-Policy': 'strict-origin-when-cross-origin'
|
934
|
+
},
|
935
|
+
data: {
|
936
|
+
username,
|
937
|
+
donotcache: Date.now(),
|
938
|
+
},
|
939
|
+
})
|
940
|
+
|
941
|
+
return response?.data ? {
|
942
|
+
...response?.data,
|
943
|
+
cookie: response.headers['set-cookie']?.map(c => decodeURI(c.substringBefore(';'))) || []
|
944
|
+
} : null
|
945
|
+
|
946
|
+
const resultExample = {
|
947
|
+
success: true,
|
948
|
+
publickey_mod: 'ca0cfb7ffc3b6f8926f3f822c535da4ee4c6c83ed3e318b7f72c1d714ae92c02dae6ec19a011b3a8c5d10399dd58e3df9d12d7d0dc3b20856d62b2860c89fb65140ccbc11f36d3cce1373c6067ba8bcc9de2a1d0188d0ae6c23e9fdeca11dd59ae13f7fd3f750b8f6f921d62279edef90b9726e421c98a511a9c62c3f65a8587285bed3be8dda32eee74d9fecbb1243833f0ddf8c19eaa22847aa736675e32560d4a59695bf90dc22eb2f2879364dbc6ac86ae3aee1cd7fb0a444471735d45a00250f96ec5fe60fea257ad7b1699153e790dc3a102d1c0cb5b2f3e1844dbc1409f60ff7f29be771afacd22e3aeb879ed0e0e9e9c2fb9ab0d9a2142c6462d9e61',
|
949
|
+
publickey_exp: '010001',
|
950
|
+
timestamp: '403345600000',
|
951
|
+
token_gid: '2be211c91a7dd170'
|
952
|
+
}
|
953
|
+
}
|
954
|
+
|
955
|
+
static async oAuthLogin(steamguard, access_token) {
|
956
|
+
steamguard = steamguard.split('||')
|
957
|
+
const steamID = (new SteamID(steamguard[0])).getSteamID64()
|
958
|
+
const sessionID = this.generateSessionID()
|
959
|
+
let result = await request({
|
960
|
+
url: `https://api.steampowered.com/IMobileAuthService/GetWGToken/v1/`,
|
961
|
+
method: 'POST',
|
962
|
+
headers: {
|
963
|
+
'Content-Type': 'multipart/form-data'
|
964
|
+
},
|
965
|
+
data: {
|
966
|
+
access_token,
|
967
|
+
},
|
968
|
+
})
|
969
|
+
|
970
|
+
if(result?.data?.response?.token) {
|
971
|
+
const cookies = ['steamLogin=' + encodeURIComponent(steamID + '||' + result?.data?.response?.token), 'steamLoginSecure=' + encodeURIComponent(steamID + '||' + result?.data?.response?.token_secure), 'steamMachineAuth' + steamID + '=' + steamguard[1], 'sessionid=' + sessionID]
|
972
|
+
return {
|
973
|
+
sessionID,
|
974
|
+
cookies,
|
975
|
+
steamID: steamID,
|
976
|
+
}
|
977
|
+
}
|
978
|
+
else {
|
979
|
+
return false
|
980
|
+
}
|
981
|
+
}
|
982
|
+
|
983
|
+
/**
|
984
|
+
*
|
985
|
+
* end static functions
|
986
|
+
*
|
987
|
+
* */
|
988
|
+
|
989
|
+
|
990
|
+
_formatHttpRequest(params) {
|
991
|
+
if(typeof params === 'string') {
|
992
|
+
params = {
|
993
|
+
url: params,
|
994
|
+
method: 'GET',
|
995
|
+
}
|
996
|
+
}
|
997
|
+
|
998
|
+
if(!(params.headers instanceof Header)) {
|
999
|
+
params.headers = new Header(params.headers)
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
params.headers.set({
|
1003
|
+
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
1004
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
1005
|
+
'Cache-Control': 'no-cache',
|
1006
|
+
Connection: 'keep-alive',
|
1007
|
+
Pragma: 'no-cache',
|
1008
|
+
'Sec-Fetch-Dest': 'document',
|
1009
|
+
'Sec-Fetch-Mode': 'navigate',
|
1010
|
+
'Sec-Fetch-Site': 'none',
|
1011
|
+
'Sec-Fetch-User': '?1',
|
1012
|
+
'Upgrade-Insecure-Requests': '1',
|
1013
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
|
1014
|
+
'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"',
|
1015
|
+
'sec-ch-ua-mobile': '?0',
|
1016
|
+
'sec-ch-ua-platform': '"Windows"',
|
1017
|
+
Cookie: this._cookies,
|
1018
|
+
})
|
1019
|
+
|
1020
|
+
let referer = params.headers.get('referer')
|
1021
|
+
if(!referer) {
|
1022
|
+
referer = SteamcommunityURL
|
1023
|
+
const URLReferer = URL.parse(params.url)
|
1024
|
+
if(URLReferer.protocol && URLReferer.host) {
|
1025
|
+
referer = URLReferer.protocol + '//' + URLReferer.host
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
params.headers.set({
|
1029
|
+
Referer: referer,
|
1030
|
+
})
|
1031
|
+
|
1032
|
+
if(!params.data) {
|
1033
|
+
params.data = {}
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
params.referrerPolicy = 'strict-origin-when-cross-origin'
|
1037
|
+
|
1038
|
+
if(!params.method) {
|
1039
|
+
params.method = 'GET'
|
1040
|
+
}
|
1041
|
+
params.method = params.method.toUpperCase()
|
1042
|
+
|
1043
|
+
return params
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
static _isPlsLoginFirst(data) {
|
1047
|
+
try {
|
1048
|
+
if(data?.includes(`<p>Please login first.</p>`)) {
|
1049
|
+
return true
|
1050
|
+
}
|
1051
|
+
} catch (e) {
|
1052
|
+
}
|
1053
|
+
return false
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
async _httpRequest(params) {
|
1057
|
+
let result = null,
|
1058
|
+
i = 0
|
1059
|
+
params = this._formatHttpRequest(params)
|
1060
|
+
|
1061
|
+
if(!this._cookies) {
|
1062
|
+
throw new Error('You jave not set cookie yet')
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
if(params.method.toUpperCase() === 'POST') {
|
1066
|
+
if(params.data instanceof URLSearchParams) {
|
1067
|
+
params.data.append('sessionid', this._sessionid)
|
1068
|
+
params.data.append('sessionID', this._sessionid)
|
1069
|
+
}
|
1070
|
+
else if(typeof params.data === 'string') {
|
1071
|
+
params.data += '&sessionid=' + this._sessionid
|
1072
|
+
params.data += '&sessionID=' + this._sessionid
|
1073
|
+
}
|
1074
|
+
else {
|
1075
|
+
params.data.sessionid = params.data.sessionID = this._sessionid
|
1076
|
+
|
1077
|
+
// if(!params.headers.get('content-type')) {
|
1078
|
+
// const formData = new URLSearchParams()
|
1079
|
+
// for (let key in params.data) {
|
1080
|
+
// formData.append(key, params.data[key])
|
1081
|
+
// }
|
1082
|
+
// params.data = formData
|
1083
|
+
// }
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
if(params.data instanceof URLSearchParams) {
|
1087
|
+
params.headers.set('content-type', 'application/x-www-form-urlencoded')
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
while (!result && i++ < MAX_RETRY) {
|
1093
|
+
const config = {
|
1094
|
+
baseURL: SteamcommunityURL, ...params,
|
1095
|
+
data: typeof params.data === 'object' && !Object.keys(params.data).length ? undefined : params.data,
|
1096
|
+
headers: params.headers.get(),
|
1097
|
+
beforeRedirect: (options, {headers}) => {
|
1098
|
+
if(options.hostname === 'steamcommunity.com') {
|
1099
|
+
options.headers.cookie = this._cookies
|
1100
|
+
}
|
1101
|
+
if(headers.location.startsWith('https://login.steampowered.com/jwt/refresh')) {
|
1102
|
+
//should login first
|
1103
|
+
}
|
1104
|
+
},
|
1105
|
+
}
|
1106
|
+
|
1107
|
+
let plsLoginFirst = false
|
1108
|
+
|
1109
|
+
result = await request(config)
|
1110
|
+
if(result.status === 429) {
|
1111
|
+
console.log('Too Many Requests')
|
1112
|
+
await sleep(60000)
|
1113
|
+
result = await request(config)
|
1114
|
+
}
|
1115
|
+
if(result?.error?.code === 'ERR_FR_TOO_MANY_REDIRECTS') {
|
1116
|
+
//Maximum number of redirects exceeded
|
1117
|
+
plsLoginFirst = true
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
if(SteamUser._isPlsLoginFirst(result?.data?.data)) {
|
1121
|
+
plsLoginFirst = true
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
if(plsLoginFirst) {
|
1125
|
+
console.error(params.url, `Please login first`)
|
1126
|
+
return {
|
1127
|
+
data: null,
|
1128
|
+
headers: config.headers
|
1129
|
+
}
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
return result
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
async _httpRequestAjax(params) {
|
1137
|
+
params = this._formatHttpRequest(params)
|
1138
|
+
const headers = params.headers instanceof Header ? params.headers : new Header(_.cloneDeep(params.headers))
|
1139
|
+
params.headers = headers.set({
|
1140
|
+
'X-KL-Ajax-Request': 'Ajax_Request',
|
1141
|
+
'X-Prototype-Version': '1.7',
|
1142
|
+
'X-Requested-With': 'XMLHttpRequest',
|
1143
|
+
}).get()
|
1144
|
+
return await this._httpRequest(params)
|
1145
|
+
}
|
1146
|
+
|
1147
|
+
static RequestXML_TooManyRequests = 0
|
1148
|
+
|
1149
|
+
static async _httpRequestXML(link) {
|
1150
|
+
if(SteamUser.RequestXML_TooManyRequests && (new Date()).getTime() - SteamUser.RequestXML_TooManyRequests < 60000) {
|
1151
|
+
return
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
const resultXml = (await request(link))?.data
|
1155
|
+
if(resultXml?.includes(`An error was encountered while processing your request:`) && resultXml?.includes(`You've made too many requests recently. Please wait and try your request again later.`)) {
|
1156
|
+
//log
|
1157
|
+
SteamUser.RequestXML_TooManyRequests = (new Date()).getTime()
|
1158
|
+
}
|
1159
|
+
else {
|
1160
|
+
SteamUser.RequestXML_TooManyRequests = 0
|
1161
|
+
}
|
1162
|
+
return resultXml
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
|
1166
|
+
async getQuickInviteData() {
|
1167
|
+
const {data} = await this._httpRequestAjax({
|
1168
|
+
url: `invites/ajaxcreate`,
|
1169
|
+
data: {
|
1170
|
+
steamid_user: this.getSteamidUser(),
|
1171
|
+
duration: 2592000, //30 days
|
1172
|
+
},
|
1173
|
+
headers: {
|
1174
|
+
'content-type': 'multipart/form-data',
|
1175
|
+
},
|
1176
|
+
method: 'POST',
|
1177
|
+
})
|
1178
|
+
return data?.success === 1 ? {
|
1179
|
+
...data.invite,
|
1180
|
+
steamid_user: this.getSteamidUser()
|
1181
|
+
} : null
|
1182
|
+
|
1183
|
+
const resultExample = {
|
1184
|
+
success: 1,
|
1185
|
+
token: 'MQNWBHQV',
|
1186
|
+
invite: {
|
1187
|
+
invite_token: 'MQNWBHQV',
|
1188
|
+
invite_limit: '1',
|
1189
|
+
invite_duration: '2592000',
|
1190
|
+
time_created: 1659976435,
|
1191
|
+
valid: 1,
|
1192
|
+
success: 1,
|
1193
|
+
rwgrsn: -2,
|
1194
|
+
steamid_user: '76561199040402348',
|
1195
|
+
}
|
1196
|
+
}
|
1197
|
+
const errorExample = {
|
1198
|
+
success: 'false',
|
1199
|
+
error: 15
|
1200
|
+
}
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
//add friend link
|
1204
|
+
async getQuickInviteLink() {
|
1205
|
+
const short_url = `https://s.team/p/${SteamUser.createFriendCode(this.getSteamidUser())}`
|
1206
|
+
const quickInviteData = await this.getQuickInviteData()
|
1207
|
+
return quickInviteData?.invite_token ? `${short_url}/${quickInviteData?.invite_token}` : null
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
async getCurrentQuickInviteTokens() {
|
1211
|
+
return (await this._httpRequest(`invites/ajaxgetall?sessionid=${this._sessionid}`))?.data
|
1212
|
+
const successExample = {
|
1213
|
+
success: 1,
|
1214
|
+
tokens: [{
|
1215
|
+
invite_token: 'hrcchjjm',
|
1216
|
+
invite_limit: '1',
|
1217
|
+
invite_duration: '2591695',
|
1218
|
+
time_created: 1662777551,
|
1219
|
+
valid: 1
|
1220
|
+
}, {
|
1221
|
+
invite_token: 'kwmppbvm',
|
1222
|
+
invite_limit: '1',
|
1223
|
+
invite_duration: '2591702',
|
1224
|
+
time_created: 1662777558,
|
1225
|
+
valid: 1
|
1226
|
+
}, {
|
1227
|
+
invite_token: 'vpghcgjp',
|
1228
|
+
invite_limit: '1',
|
1229
|
+
invite_duration: '2584709',
|
1230
|
+
time_created: 1662770565,
|
1231
|
+
valid: 1
|
1232
|
+
}]
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
|
1237
|
+
//{ success: 1 }
|
1238
|
+
//{ success: 91 }
|
1239
|
+
//{ success: 8 }//link expires
|
1240
|
+
async acceptQuickInviteData(quickInviteData) {
|
1241
|
+
return (await this._httpRequest(`invites/ajaxredeem?sessionid=${this._sessionid}&steamid_user=${quickInviteData.steamid_user}&invite_token=${quickInviteData.invite_token}`))?.data
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
async acceptQuickInviteLink(quickInviteLink) {
|
1245
|
+
const invite_token = quickInviteLink.removeSuffix('/').substringAfterLast('/')
|
1246
|
+
const result = await this._httpRequest(quickInviteLink)
|
1247
|
+
if(!result.data) {
|
1248
|
+
return
|
1249
|
+
}
|
1250
|
+
let g_rgProfileData = JSON_parse(result.data.substringBetweenOrNull('g_rgProfileData = ', '"};') + '"}')
|
1251
|
+
if(!g_rgProfileData) {
|
1252
|
+
return
|
1253
|
+
}
|
1254
|
+
const quickInviteData = {
|
1255
|
+
invite_token,
|
1256
|
+
steamid_user: g_rgProfileData.steamid,
|
1257
|
+
}
|
1258
|
+
return await this.acceptQuickInviteData(quickInviteData)
|
1259
|
+
}
|
1260
|
+
|
1261
|
+
_parseComments(html) {
|
1262
|
+
const $ = cheerio.load(`<div>${html}</div>`)
|
1263
|
+
const comments = []
|
1264
|
+
$('.commentthread_comment').each(function () {
|
1265
|
+
const el = $(this)
|
1266
|
+
const content = el.find('.commentthread_comment_text').text().trim()
|
1267
|
+
const id = el.attr('id')//comment_3452590876711274713
|
1268
|
+
const commentID = id.substringAfter('comment_')
|
1269
|
+
const avatar = el.find('.commentthread_comment_avatar > a > img').attr('src')
|
1270
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL(avatar)
|
1271
|
+
const commentthread_comment_author = el.find('.commentthread_comment_author > a')
|
1272
|
+
const profileURL = commentthread_comment_author.attr('href')
|
1273
|
+
const miniprofile = parseInt(commentthread_comment_author.attr('data-miniprofile'))
|
1274
|
+
const name = commentthread_comment_author.text()?.trim()
|
1275
|
+
const timestamp = parseInt(el.find('.commentthread_comment_timestamp').attr('data-timestamp'))
|
1276
|
+
const steamID = SteamUser.miniprofile2SteamID64(miniprofile)
|
1277
|
+
|
1278
|
+
comments.push({
|
1279
|
+
id: commentID,
|
1280
|
+
content,
|
1281
|
+
timestamp,
|
1282
|
+
author: {
|
1283
|
+
steamID,
|
1284
|
+
profileURL,
|
1285
|
+
customURL: SteamUser.getCustomURL_from_ProfileURL(profileURL),
|
1286
|
+
miniprofile,
|
1287
|
+
name,
|
1288
|
+
avatar,
|
1289
|
+
avatarHash,
|
1290
|
+
}
|
1291
|
+
})
|
1292
|
+
})
|
1293
|
+
return comments
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
async getMyComments() {
|
1297
|
+
return await this.getUserComments()
|
1298
|
+
}
|
1299
|
+
|
1300
|
+
async getUserComments(steamID = this.getSteamidUser()) {
|
1301
|
+
const result = await this._httpRequest(`comment/Profile/render/${steamID}/-1/`)
|
1302
|
+
if(!result.data) {
|
1303
|
+
return []
|
1304
|
+
}
|
1305
|
+
const {
|
1306
|
+
total_count,
|
1307
|
+
pagesize,
|
1308
|
+
comments_html
|
1309
|
+
} = result.data
|
1310
|
+
|
1311
|
+
let comments = this._parseComments(comments_html)
|
1312
|
+
if(comments.length < total_count) {
|
1313
|
+
let i = comments.length
|
1314
|
+
const queue = []
|
1315
|
+
while (i <= total_count) {
|
1316
|
+
queue.push(this._httpRequest({
|
1317
|
+
url: `comment/Profile/render/${steamID}/-1/`,
|
1318
|
+
data: {
|
1319
|
+
start: Math.min(i, total_count),
|
1320
|
+
totalcount: total_count,
|
1321
|
+
count: pagesize,
|
1322
|
+
feature2: -1,
|
1323
|
+
},
|
1324
|
+
method: 'POST'
|
1325
|
+
}))
|
1326
|
+
i += pagesize
|
1327
|
+
}
|
1328
|
+
const results = await Promise.all(queue)
|
1329
|
+
comments = comments.concat(this._parseComments(results
|
1330
|
+
.filter(result => result?.data?.comments_html)
|
1331
|
+
.map(result => result.data.comments_html.trim())
|
1332
|
+
.join('')))
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
return comments
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
static _formatGroupLink({
|
1339
|
+
link,
|
1340
|
+
gid,
|
1341
|
+
groupURL,
|
1342
|
+
page,
|
1343
|
+
content_only,
|
1344
|
+
searchKey,
|
1345
|
+
pathname = '',
|
1346
|
+
}) {
|
1347
|
+
searchKey = searchKey?.trim?.()
|
1348
|
+
if(!link) {
|
1349
|
+
link = gid ? `gid/${gid}/?p=${page}` : `groups/${groupURL}/?p=${page}`
|
1350
|
+
}
|
1351
|
+
link = new Url(link)
|
1352
|
+
link.query = '?' + [...link.query.removePrefix('?')
|
1353
|
+
.split('&')
|
1354
|
+
.map(q => q.split('='))
|
1355
|
+
.filter(q => !['searchKey', 'content_only'].includes(q[0]))
|
1356
|
+
.map(q => q.join('=')), !!content_only && `content_only=true`, !!searchKey && `searchKey=${encodeURIComponent(searchKey)}`]
|
1357
|
+
.filter(Boolean).join('&')
|
1358
|
+
|
1359
|
+
if(pathname) {
|
1360
|
+
let _pathname = link.pathname.removeSuffix('/')
|
1361
|
+
if(!_pathname.endsWith(pathname)) {
|
1362
|
+
link.pathname = _pathname + '/' + pathname + '/'
|
1363
|
+
}
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
Object.assign(link, _.pick((new Url(SteamcommunityURL)), ['slashes', 'host', 'hostname', 'origin', 'protocol']))
|
1367
|
+
if(link.pathname && !link.pathname.startsWith('/')) {
|
1368
|
+
link.pathname = '/' + link.pathname
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
return link.toString()
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
static _parseGroupInfo(html) {
|
1375
|
+
if(!html) {
|
1376
|
+
return null
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
let nextPage = null
|
1380
|
+
let prevPage = null
|
1381
|
+
let nextPageLink = null
|
1382
|
+
let totalPages = -1
|
1383
|
+
const $ = cheerio.load(html)
|
1384
|
+
let gid
|
1385
|
+
if(html.includes('InitializeCommentThread') && html.includes('https://steamcommunity.com/comment/Clan')) {
|
1386
|
+
gid = html.substringBetweenOrNull(`InitializeCommentThread( "Clan", "Clan_`, `",`)
|
1387
|
+
}
|
1388
|
+
if(!gid) {
|
1389
|
+
gid = $('#reportAbuseModalContents form input[name="abuseID"]').val()
|
1390
|
+
}
|
1391
|
+
if(!gid) {
|
1392
|
+
gid = $('.content .joinchat_bg').attr('onclick')?.substringBetweenOrNull(`'`, `'`)
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
$('.grouppage_header_abbrev').remove()
|
1396
|
+
const groupName = html.substringBetweenOrNull(`g_strGroupName = "`, `";`) || $('.grouppage_header_name').text()?.trim()
|
1397
|
+
|
1398
|
+
let _groupURL = html.substringBetweenOrNull(`InitGroupPage( 'https://steamcommunity.com/groups/`, `',`) || $('#group_tab_overview').attr('href')?.substringAfter('https://steamcommunity.com/groups/') || $('#searchEditForm[action]').attr('action')?.substringAfter('https://steamcommunity.com/groups/')?.substringBefore('/')
|
1399
|
+
_groupURL = _groupURL?.removeSuffix('/')
|
1400
|
+
const headline = $('.maincontent .group_summary > h1').text()?.trim()
|
1401
|
+
|
1402
|
+
let summary = $('.maincontent .group_summary .formatted_group_summary').html()?.replaceAll(/[\t\n\r]/gi, '')
|
1403
|
+
for (let i = 1; i < SteamImageCDN.length; i++) {
|
1404
|
+
summary = summary.replaceAll(SteamImageCDN[i], SteamImageCDN[0])
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL($('.grouppage_logo img[src]').attr('src') || $('.grouppage_resp_logo img[src]').attr('src'))
|
1408
|
+
let memberCount = [...$('.group_paging')]
|
1409
|
+
.map(g => $(g).text()?.trim())
|
1410
|
+
.find(text => text?.endsWith('Members'))
|
1411
|
+
?.substringBeforeLast('Members')
|
1412
|
+
?.trim()
|
1413
|
+
if(memberCount) {
|
1414
|
+
if(memberCount.includes('of')) {
|
1415
|
+
memberCount = memberCount.substringAfterLast('of')
|
1416
|
+
}
|
1417
|
+
memberCount = parseInt(memberCount.trim().replaceAll(',', ''))
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
const membersInChat = SteamUser._formatString2Int($($('.joinchat_bg .joinchat_membercount .count')[0]).text())
|
1421
|
+
|
1422
|
+
const groupmemberstat = [...$('.membercount')].map(groupstat => ({
|
1423
|
+
label: $(groupstat).find('.label').text()?.trim(),
|
1424
|
+
className: $(groupstat).attr('class')?.split(' ') || [],
|
1425
|
+
count: SteamUser._formatString2Int($(groupstat).find('.count').text()),
|
1426
|
+
}))
|
1427
|
+
|
1428
|
+
const memberDetailCount = groupmemberstat.find(({className}) => className.includes('members'))?.count
|
1429
|
+
const membersInGame = groupmemberstat.find(({className}) => className.includes('ingame'))?.count
|
1430
|
+
const membersOnline = groupmemberstat.find(({className}) => className.includes('online'))?.count
|
1431
|
+
|
1432
|
+
const startingMember = -1
|
1433
|
+
const members = []
|
1434
|
+
const groupstat = [...$('.groupstat')].map(groupstat => ({
|
1435
|
+
label: $(groupstat).find('.label').text()?.trim(),
|
1436
|
+
data: $(groupstat).find('.data').text()?.trim(),
|
1437
|
+
}))
|
1438
|
+
const foundedStr = groupstat.find(({label}) => label?.toLowerCase() === 'Founded'.toLowerCase())?.data
|
1439
|
+
let founded
|
1440
|
+
if((founded = moment(foundedStr, 'DD MMMM, YYYY')).isValid()) {
|
1441
|
+
founded = founded.valueOf()
|
1442
|
+
}
|
1443
|
+
else {
|
1444
|
+
founded = null
|
1445
|
+
}
|
1446
|
+
const language = groupstat.find(({label}) => label?.toLowerCase() === 'Language'.toLowerCase())?.data
|
1447
|
+
const location = groupstat.find(({label}) => label?.toLowerCase() === 'Location'.toLowerCase())?.data
|
1448
|
+
|
1449
|
+
$(`#memberList > .member_block`).each(function () {
|
1450
|
+
const el = $(this)
|
1451
|
+
let linkFriend = el.find(`a.linkFriend`)
|
1452
|
+
let avatarHash = SteamUser.GetAvatarHashFromURL(el.find(`a > img`).attr('src'))
|
1453
|
+
const link = linkFriend.attr('href')
|
1454
|
+
const name = linkFriend.text()
|
1455
|
+
const miniprofile = parseInt(el.attr('data-miniprofile'))
|
1456
|
+
const steamID = SteamUser.miniprofile2SteamID64(miniprofile)
|
1457
|
+
|
1458
|
+
const rank_icon = el.find('> .rank_icon[title]').attr('title')?.trim()
|
1459
|
+
// const rank_icon_src = el.find('> .rank_icon img').attr('src')?.toLowerCase()?.substringBetweenOrNull(`/images/skin_1/`, `.`)
|
1460
|
+
const rank = rank_icon && (Object.entries(EGroupRank)
|
1461
|
+
.find(([key, ranks]) => ranks.some(rank => rank.toLowerCase() === rank_icon.toLowerCase())))?.[0]
|
1462
|
+
|
1463
|
+
|
1464
|
+
members.push({
|
1465
|
+
link,
|
1466
|
+
steamID,
|
1467
|
+
miniprofile,
|
1468
|
+
name,
|
1469
|
+
avatarHash,
|
1470
|
+
customURL: SteamUser.getCustomURL_from_ProfileURL(link),
|
1471
|
+
rank_icon,
|
1472
|
+
rank, // rank_icon_src,
|
1473
|
+
})
|
1474
|
+
})
|
1475
|
+
|
1476
|
+
$('.pagebtn[href]').each(function () {
|
1477
|
+
const el = $(this)
|
1478
|
+
const text = el.text()?.trim()
|
1479
|
+
const _page = parseInt(el.attr('href').substringAfter('p=')) || -1
|
1480
|
+
|
1481
|
+
if(_page) {
|
1482
|
+
totalPages = Math.max(totalPages, _page)
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
if(text === '>') {
|
1486
|
+
const _nextPageLink = el.attr('href')?.replace(`#members`, `/members`)
|
1487
|
+
const _nextPage = parseInt(_nextPageLink.substringAfter('p='))
|
1488
|
+
if(!isNaN(_nextPage)) {
|
1489
|
+
nextPage = _nextPage
|
1490
|
+
nextPageLink = _nextPageLink
|
1491
|
+
}
|
1492
|
+
}
|
1493
|
+
else if(text === '<') {
|
1494
|
+
const _prevPage = parseInt(el.attr('href').substringAfter('p='))
|
1495
|
+
if(!isNaN(_prevPage)) {
|
1496
|
+
prevPage = _prevPage
|
1497
|
+
}
|
1498
|
+
}
|
1499
|
+
})
|
1500
|
+
|
1501
|
+
const g_strLanguage = html.substringBetweenOrNull(`g_strLanguage = "`, `";`)
|
1502
|
+
|
1503
|
+
return {
|
1504
|
+
id: gid,
|
1505
|
+
name: groupName,
|
1506
|
+
url: _groupURL,
|
1507
|
+
headline: headline,
|
1508
|
+
summary: summary,
|
1509
|
+
avatarHash: avatarHash,
|
1510
|
+
memberCount: memberCount,
|
1511
|
+
memberDetailCount: memberDetailCount,
|
1512
|
+
membersInChat: membersInChat,
|
1513
|
+
membersInGame: membersInGame,
|
1514
|
+
membersOnline: membersOnline,
|
1515
|
+
totalPages: totalPages,
|
1516
|
+
currentPage: nextPage - 1,
|
1517
|
+
nextPage: nextPage,
|
1518
|
+
nextPageLink: nextPageLink,
|
1519
|
+
startingMember: startingMember,
|
1520
|
+
members: members,
|
1521
|
+
founded: founded,
|
1522
|
+
foundedStr: foundedStr,
|
1523
|
+
language: language,
|
1524
|
+
location: location,
|
1525
|
+
g_strLanguage,
|
1526
|
+
}
|
1527
|
+
}
|
1528
|
+
|
1529
|
+
async getGroupOverview({
|
1530
|
+
groupURL,
|
1531
|
+
gid,
|
1532
|
+
page = 1,
|
1533
|
+
content_only,
|
1534
|
+
searchKey,
|
1535
|
+
}) {
|
1536
|
+
return await SteamUser.getGroupOverview({
|
1537
|
+
groupURL,
|
1538
|
+
gid,
|
1539
|
+
page,
|
1540
|
+
cookie: this.getCookies(),
|
1541
|
+
content_only,
|
1542
|
+
searchKey,
|
1543
|
+
})
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
static async getGroupOverview({
|
1547
|
+
groupURL,
|
1548
|
+
gid,
|
1549
|
+
page = 1,
|
1550
|
+
cookie,
|
1551
|
+
link,
|
1552
|
+
content_only,
|
1553
|
+
searchKey,
|
1554
|
+
}) {
|
1555
|
+
link = SteamUser._formatGroupLink({
|
1556
|
+
link,
|
1557
|
+
gid,
|
1558
|
+
groupURL,
|
1559
|
+
page,
|
1560
|
+
content_only,
|
1561
|
+
searchKey,
|
1562
|
+
})
|
1563
|
+
const result = await request({
|
1564
|
+
baseURL: SteamcommunityURL,
|
1565
|
+
url: link,
|
1566
|
+
headers: {...cookie && {cookie}},
|
1567
|
+
})
|
1568
|
+
return SteamUser._parseGroupInfo(result?.data)
|
1569
|
+
}
|
1570
|
+
|
1571
|
+
async getGroupMembers({
|
1572
|
+
groupURL,
|
1573
|
+
gid,
|
1574
|
+
page = 1,
|
1575
|
+
link,
|
1576
|
+
content_only,
|
1577
|
+
searchKey,
|
1578
|
+
}) {
|
1579
|
+
return await SteamUser.getGroupMembers({
|
1580
|
+
groupURL,
|
1581
|
+
gid,
|
1582
|
+
page,
|
1583
|
+
cookie: this.getCookies(),
|
1584
|
+
link,
|
1585
|
+
content_only,
|
1586
|
+
searchKey,
|
1587
|
+
})
|
1588
|
+
}
|
1589
|
+
|
1590
|
+
static async getGroupMembers({
|
1591
|
+
groupURL,
|
1592
|
+
gid,
|
1593
|
+
page = 1,
|
1594
|
+
cookie,
|
1595
|
+
link,
|
1596
|
+
content_only,
|
1597
|
+
searchKey,
|
1598
|
+
}) {
|
1599
|
+
link = SteamUser._formatGroupLink({
|
1600
|
+
link,
|
1601
|
+
gid,
|
1602
|
+
groupURL,
|
1603
|
+
page,
|
1604
|
+
content_only,
|
1605
|
+
searchKey,
|
1606
|
+
pathname: 'members'
|
1607
|
+
})
|
1608
|
+
|
1609
|
+
const result = await request({
|
1610
|
+
baseURL: SteamcommunityURL,
|
1611
|
+
url: link,
|
1612
|
+
headers: {...cookie && {cookie}},
|
1613
|
+
})
|
1614
|
+
return SteamUser._parseGroupInfo(result?.data)
|
1615
|
+
}
|
1616
|
+
|
1617
|
+
async getGroupMembersFull({
|
1618
|
+
groupURL,
|
1619
|
+
gid,
|
1620
|
+
cookie,
|
1621
|
+
cbOnMember,
|
1622
|
+
cbOnMembers,
|
1623
|
+
content_only,
|
1624
|
+
searchKey,
|
1625
|
+
}) {
|
1626
|
+
return await SteamUser.getGroupMembersFull({
|
1627
|
+
groupURL,
|
1628
|
+
gid,
|
1629
|
+
cookie: this.getCookies(),
|
1630
|
+
cbOnMember,
|
1631
|
+
cbOnMembers,
|
1632
|
+
content_only,
|
1633
|
+
searchKey,
|
1634
|
+
})
|
1635
|
+
}
|
1636
|
+
|
1637
|
+
static async getGroupMembersFull({
|
1638
|
+
groupURL,
|
1639
|
+
gid,
|
1640
|
+
cookie,
|
1641
|
+
cbOnMember,
|
1642
|
+
cbOnMembers,
|
1643
|
+
content_only,
|
1644
|
+
searchKey,
|
1645
|
+
}) {
|
1646
|
+
let group
|
1647
|
+
do {
|
1648
|
+
group = await SteamUser.getGroupMembers({
|
1649
|
+
...(group?.nextPageLink ? {link: group.nextPageLink} : {
|
1650
|
+
gid: gid,
|
1651
|
+
groupURL: groupURL
|
1652
|
+
}),
|
1653
|
+
cookie,
|
1654
|
+
content_only,
|
1655
|
+
searchKey,
|
1656
|
+
})
|
1657
|
+
if(Array.isArray(group?.members)) {
|
1658
|
+
typeof cbOnMembers === 'function' && cbOnMembers(group.members)
|
1659
|
+
typeof cbOnMember === 'function' && group.members.forEach(cbOnMember)
|
1660
|
+
}
|
1661
|
+
} while (group?.nextPageLink)
|
1662
|
+
}
|
1663
|
+
|
1664
|
+
static async getGroupInfoXML({
|
1665
|
+
groupURL,
|
1666
|
+
gid,
|
1667
|
+
page = 1,
|
1668
|
+
link,
|
1669
|
+
}) {
|
1670
|
+
if(!link) {
|
1671
|
+
link = gid ? `/gid/${gid}/memberslistxml/?xml=1&p=${page}` : `/groups/${groupURL}/memberslistxml/?xml=1&p=${page}`
|
1672
|
+
}
|
1673
|
+
const resultXml = await request({
|
1674
|
+
baseURL: SteamcommunityURL,
|
1675
|
+
url: link,
|
1676
|
+
})
|
1677
|
+
if(!resultXml?.data) {
|
1678
|
+
return
|
1679
|
+
}
|
1680
|
+
if(resultXml.status === 503) {
|
1681
|
+
console.log('Service Unavailable')
|
1682
|
+
return
|
1683
|
+
}
|
1684
|
+
if(resultXml.status === 429) {
|
1685
|
+
console.log('Too Many Requests')
|
1686
|
+
return
|
1687
|
+
}
|
1688
|
+
const result = getJSObjectFronXML(resultXml.data)?.memberList
|
1689
|
+
if(!result) {
|
1690
|
+
return
|
1691
|
+
}
|
1692
|
+
return {
|
1693
|
+
id: result.groupID64,
|
1694
|
+
name: result.groupDetails.groupName,
|
1695
|
+
url: result.groupDetails.groupURL,
|
1696
|
+
headline: result.groupDetails.headline,
|
1697
|
+
summary: result.groupDetails.summary,
|
1698
|
+
avatarHash: SteamUser.GetAvatarHashFromMultipleURL([result.groupDetails.avatarIcon, result.groupDetails.avatarMedium, result.groupDetails.avatarFull]),
|
1699
|
+
memberCount: SteamUser._formatString2Int(result.memberCount),
|
1700
|
+
memberDetailCount: SteamUser._formatString2Int(result.groupDetails.memberCount),
|
1701
|
+
membersInChat: SteamUser._formatString2Int(result.groupDetails.membersInChat),
|
1702
|
+
membersInGame: SteamUser._formatString2Int(result.groupDetails.membersInGame),
|
1703
|
+
membersOnline: SteamUser._formatString2Int(result.groupDetails.membersOnline),
|
1704
|
+
totalPages: SteamUser._formatString2Int(result.totalPages),
|
1705
|
+
currentPage: SteamUser._formatString2Int(result.currentPage),
|
1706
|
+
startingMember: SteamUser._formatString2Int(result.startingMember),
|
1707
|
+
nextPageLink: result.nextPageLink,
|
1708
|
+
members: result.members.steamID64,//['76561198072779605', '76561198017622621']
|
1709
|
+
}
|
1710
|
+
}
|
1711
|
+
|
1712
|
+
static async getGroupInfoXMLFull({
|
1713
|
+
groupURL,
|
1714
|
+
gid,
|
1715
|
+
cbOnMembers,
|
1716
|
+
}) {
|
1717
|
+
let group = null,
|
1718
|
+
members = [],
|
1719
|
+
groupInfo = null
|
1720
|
+
do {
|
1721
|
+
group = await SteamUser.getGroupInfoXML({
|
1722
|
+
...(group?.nextPageLink ? {link: group.nextPageLink} : {
|
1723
|
+
gid: gid,
|
1724
|
+
groupURL: groupURL,
|
1725
|
+
}),
|
1726
|
+
})
|
1727
|
+
if(group && !groupInfo) {
|
1728
|
+
groupInfo = group
|
1729
|
+
}
|
1730
|
+
if(Array.isArray(group?.members)) {
|
1731
|
+
members = members.concat(group?.members)
|
1732
|
+
typeof cbOnMembers === 'function' && cbOnMembers(group.members)//list of steam id
|
1733
|
+
}
|
1734
|
+
} while (group?.nextPageLink)
|
1735
|
+
return {
|
1736
|
+
...groupInfo,
|
1737
|
+
nextPageLink: undefined,
|
1738
|
+
members,
|
1739
|
+
}
|
1740
|
+
}
|
1741
|
+
|
1742
|
+
async _parseFriendList(result) {
|
1743
|
+
const $ = cheerio.load(result?.data || result || '')
|
1744
|
+
const results = []
|
1745
|
+
const friendList = $(`.persona[data-miniprofile]`)
|
1746
|
+
if(!friendList || !friendList.length) {
|
1747
|
+
return []
|
1748
|
+
}
|
1749
|
+
|
1750
|
+
friendList.each(function () {
|
1751
|
+
const el = $(this)
|
1752
|
+
const profileURL = el.find('a.selectable_overlay[data-container]').attr('href') || el.find('a.friendBlockLinkOverlay').attr('href')
|
1753
|
+
let friendBlockContent = el.find(`.friend_block_content, .friendBlockContent`)
|
1754
|
+
const playerAvatar = el.find(`.player_avatar, .playerAvatar`).find('img')
|
1755
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL(playerAvatar.attr('src'))
|
1756
|
+
const avatar = SteamUser.GetAvatarURLFromHash(avatarHash, 'full')
|
1757
|
+
|
1758
|
+
const isNickname = !!friendBlockContent.find('.player_nickname_hint').length
|
1759
|
+
|
1760
|
+
const game = friendBlockContent.find(`.friend_game_link, .linkFriend_in-game`)
|
1761
|
+
.text()
|
1762
|
+
.replaceAll(/\s+/g, ' ')
|
1763
|
+
.trim()
|
1764
|
+
.removePrefix('In-Game')
|
1765
|
+
.trim()
|
1766
|
+
friendBlockContent.find(`.friend_small_text, .friendSmallText`).remove()
|
1767
|
+
|
1768
|
+
const lastOnline = friendBlockContent.find(`.friend_last_online_text`).text().replaceAll(/\s+/g, ' ').trim()
|
1769
|
+
friendBlockContent.find(`.friend_last_online_text`).remove()
|
1770
|
+
|
1771
|
+
let username = friendBlockContent.text().trim()
|
1772
|
+
if(username === '[deleted]') {
|
1773
|
+
return
|
1774
|
+
}
|
1775
|
+
|
1776
|
+
const miniprofile = parseInt(el.attr('data-miniprofile'))
|
1777
|
+
const steamId = SteamUser.miniprofile2SteamID64(miniprofile)
|
1778
|
+
let score = ''
|
1779
|
+
|
1780
|
+
let onlineStatus = ''
|
1781
|
+
if(el.hasClass('in-game')) {
|
1782
|
+
onlineStatus = 'ingame'
|
1783
|
+
}
|
1784
|
+
else if(el.hasClass('online')) {
|
1785
|
+
onlineStatus = 'online'
|
1786
|
+
}
|
1787
|
+
else if(el.hasClass('offline')) {
|
1788
|
+
onlineStatus = 'offline'
|
1789
|
+
}
|
1790
|
+
|
1791
|
+
results.push({
|
1792
|
+
username,
|
1793
|
+
steamId,
|
1794
|
+
game,
|
1795
|
+
onlineStatus,
|
1796
|
+
lastOnline,
|
1797
|
+
miniprofile,
|
1798
|
+
score,
|
1799
|
+
isNickname,
|
1800
|
+
avatar,
|
1801
|
+
avatarHash,
|
1802
|
+
profileURL,
|
1803
|
+
customURL: SteamUser.getCustomURL_from_ProfileURL(profileURL),
|
1804
|
+
})
|
1805
|
+
})
|
1806
|
+
|
1807
|
+
return results
|
1808
|
+
}
|
1809
|
+
|
1810
|
+
async getFollowingPlayersList(steamID = this.getSteamidUser()) {
|
1811
|
+
return (await this._parseFriendList((await this._httpRequest(`${this.getSteamUserProfileURL(steamID)}/following/`)).data))
|
1812
|
+
}
|
1813
|
+
|
1814
|
+
async getFriendsList(steamID = this.getSteamidUser()) {
|
1815
|
+
return (await this._parseFriendList((await this._httpRequest(`${this.getSteamUserProfileURL(steamID)}/friends/`)).data))
|
1816
|
+
}
|
1817
|
+
|
1818
|
+
async getMyFriendsList() {
|
1819
|
+
return await this.getFriendsList()
|
1820
|
+
}
|
1821
|
+
|
1822
|
+
async getMyFriendsIDList() {
|
1823
|
+
const {data} = await this._httpRequestAjax(`textfilter/ajaxgetfriendslist`)
|
1824
|
+
if(!data) {
|
1825
|
+
return []
|
1826
|
+
}
|
1827
|
+
return data.friendslist.friends.filter(function (friend) {
|
1828
|
+
return EFriendRelationship.Friend === friend.efriendrelationship
|
1829
|
+
}).map(function (friend) {
|
1830
|
+
return friend.ulfriendid
|
1831
|
+
})
|
1832
|
+
}
|
1833
|
+
|
1834
|
+
async getMyFollowingPlayersList() {
|
1835
|
+
const steamID = this.getSteamidUser()
|
1836
|
+
return await this.getFollowingPlayersList(steamID)
|
1837
|
+
}
|
1838
|
+
|
1839
|
+
async getMatchHistory_initial(matchHistoryType) {
|
1840
|
+
if(!matchHistoryType) {
|
1841
|
+
return
|
1842
|
+
}
|
1843
|
+
let result = await this._httpRequest(`${this.getMySteamUserProfileURL()}/gcpd/${AppID_CSGO}/?tab=${matchHistoryType}`)
|
1844
|
+
if(result?.data) {
|
1845
|
+
const matches = this._parseMatchHistory(result?.data)
|
1846
|
+
const continue_token = result.data.substringBetweenOrNull('var g_sGcContinueToken =', ';').trim().removeSurrounding('\'').trim()
|
1847
|
+
const continue_text = result.data.substringBetweenOrNull('load_more_button_continue_text" class="returnLink">', '</div>')
|
1848
|
+
return {
|
1849
|
+
continue_token,
|
1850
|
+
continue_text,
|
1851
|
+
matches
|
1852
|
+
}
|
1853
|
+
}
|
1854
|
+
else {
|
1855
|
+
return {
|
1856
|
+
continue_token: '',
|
1857
|
+
continue_text: '',
|
1858
|
+
matches: []
|
1859
|
+
}
|
1860
|
+
}
|
1861
|
+
}
|
1862
|
+
|
1863
|
+
async getClientJsToken() {
|
1864
|
+
let result = (await this._httpRequest('chat/clientjstoken')).data
|
1865
|
+
|
1866
|
+
const dataExample = {
|
1867
|
+
logged_in: true,
|
1868
|
+
steamid: '76561199040402348',
|
1869
|
+
accountid: 1080136620,
|
1870
|
+
account_name: 'henry22230',
|
1871
|
+
token: '1o7xYpbcmTsAAAAAAAAAAAAAAAAAAAAAAwCf6fVEGxM9H7Tnk5oW5QPI'
|
1872
|
+
}
|
1873
|
+
|
1874
|
+
return Object.assign(result, {
|
1875
|
+
steamID: new SteamID(result.steamid),
|
1876
|
+
accountName: result.account_name,
|
1877
|
+
webLogonToken: result.token
|
1878
|
+
})
|
1879
|
+
}
|
1880
|
+
|
1881
|
+
getClientLogonToken = this.getClientJsToken
|
1882
|
+
|
1883
|
+
async _getHistoryMatches(matchHistoryType, token) {
|
1884
|
+
const _self = this
|
1885
|
+
// console_log(`fetchIt ${token} ${matchHistoryType}`)
|
1886
|
+
let result,
|
1887
|
+
i = MAX_RETRY
|
1888
|
+
while (result?.data?.success !== true && i--) {
|
1889
|
+
result = await _self._httpRequest(`${this.getMySteamUserProfileURL()}/gcpd/${AppID_CSGO}?ajax=1&tab=${matchHistoryType}&continue_token=${token}&sessionid=${_self._sessionid}`)
|
1890
|
+
}
|
1891
|
+
if(!result.data) {
|
1892
|
+
return null
|
1893
|
+
}
|
1894
|
+
const {
|
1895
|
+
continue_token,//3568892337192960000
|
1896
|
+
continue_text,//2022-08-29
|
1897
|
+
html,
|
1898
|
+
success,//true, false
|
1899
|
+
} = result.data
|
1900
|
+
|
1901
|
+
const matches = _self._parseMatchHistory(html)
|
1902
|
+
|
1903
|
+
return {
|
1904
|
+
matches,
|
1905
|
+
continue_token,
|
1906
|
+
continue_text,
|
1907
|
+
}
|
1908
|
+
}
|
1909
|
+
|
1910
|
+
_parseMatchHistory(html) {
|
1911
|
+
return SteamUser._parseMatchHistory(html, this._miniprofile_user)
|
1912
|
+
}
|
1913
|
+
|
1914
|
+
static _parseMatchHistory(html, myMiniProfile) {
|
1915
|
+
const matches = []
|
1916
|
+
if(!html) {
|
1917
|
+
return matches
|
1918
|
+
}
|
1919
|
+
|
1920
|
+
const $ = cheerio.load(html
|
1921
|
+
.replaceAll(/[\t\n\r]/gi, '')
|
1922
|
+
.trim())
|
1923
|
+
|
1924
|
+
$('table.csgo_scoreboard_inner_right').each(function () {
|
1925
|
+
const table = $(this)
|
1926
|
+
|
1927
|
+
const matchesEl = table.parents('tr')
|
1928
|
+
const matchInfo = {}
|
1929
|
+
|
1930
|
+
matchesEl.find('td.val_left table.csgo_scoreboard_inner_left tr > td').each(function (index, tdEl) {
|
1931
|
+
tdEl = $(tdEl)
|
1932
|
+
const text = tdEl.text().trim()
|
1933
|
+
|
1934
|
+
if(text.startsWith('Competitive ')) {
|
1935
|
+
matchInfo.map = text.substringAfter('Competitive ')
|
1936
|
+
}
|
1937
|
+
else if(text.endsWith(' GMT')) {
|
1938
|
+
matchInfo.time = text
|
1939
|
+
}
|
1940
|
+
else if(text.startsWith('Wait Time: ')) {
|
1941
|
+
matchInfo.waitTime = text.substringAfter('Wait Time: ')
|
1942
|
+
}
|
1943
|
+
else if(text.startsWith('Match Duration: ')) {
|
1944
|
+
matchInfo.duration = text.substringAfter('Match Duration: ')
|
1945
|
+
}
|
1946
|
+
else if(text === 'Download GOTV Replay') {
|
1947
|
+
matchInfo.GOTV_Replay = tdEl.find('a').attr('href')
|
1948
|
+
}
|
1949
|
+
else if(text.startsWith('Viewers: ')) {
|
1950
|
+
matchInfo.viewers = parseInt(text.substringAfter('Viewers: '))
|
1951
|
+
}
|
1952
|
+
else if(text.startsWith('Ranked: Yes')) {
|
1953
|
+
matchInfo.ranked = true
|
1954
|
+
}
|
1955
|
+
else {
|
1956
|
+
console_log(text)
|
1957
|
+
}
|
1958
|
+
})
|
1959
|
+
matchInfo.ranked = !!matchInfo.ranked
|
1960
|
+
|
1961
|
+
const historyTable = table2json($, table, function ($, el, isHeader) {
|
1962
|
+
el = $(el)
|
1963
|
+
if(!isHeader && el.attr('class') === 'inner_name') {
|
1964
|
+
const link = el.find('a.linkTitle').attr('href')
|
1965
|
+
return {
|
1966
|
+
avatarHash: SteamUser.GetAvatarHashFromURL(el.find('.playerAvatar a > img[src]').attr('src')),
|
1967
|
+
name: el.text().trim(),
|
1968
|
+
link,
|
1969
|
+
miniprofile: el.find('a.linkTitle').data('miniprofile'),
|
1970
|
+
customURL: SteamUser.getCustomURL_from_ProfileURL(link),
|
1971
|
+
}
|
1972
|
+
}
|
1973
|
+
return el.text().trim()
|
1974
|
+
})
|
1975
|
+
|
1976
|
+
if(historyTable.length !== 11) {
|
1977
|
+
return
|
1978
|
+
}
|
1979
|
+
//historyTable should be array of 11 elements
|
1980
|
+
const scoreboard_score = historyTable[5]['Player Name'].split(':').map(c => parseInt(c.trim()))
|
1981
|
+
const ctScore = scoreboard_score[0]
|
1982
|
+
const tScore = scoreboard_score[1]
|
1983
|
+
const winningTeam = ctScore > tScore ? 'ct' : (ctScore < tScore ? 't' : null)
|
1984
|
+
const players = []
|
1985
|
+
|
1986
|
+
for (let i = 0; i < 11; i++) {
|
1987
|
+
if(i === 5) {
|
1988
|
+
continue
|
1989
|
+
}
|
1990
|
+
const player = historyTable[i]
|
1991
|
+
player.team = i < 5 ? 'ct' : 't'
|
1992
|
+
player.isWin = winningTeam === player.team
|
1993
|
+
player.isTie = winningTeam === null
|
1994
|
+
player.isLose = !player.isWin && !player.isTie
|
1995
|
+
player.MatchWinLose = player.isWin ? MatchWinLose.Win : (player.isTie ? MatchWinLose.Tie : MatchWinLose.Lose)
|
1996
|
+
|
1997
|
+
for (const key of ['Ping', 'K', 'A', 'D', 'Score']) {
|
1998
|
+
if(!isNaN(parseInt(player[key]))) {
|
1999
|
+
player[key] = parseInt(player[key])
|
2000
|
+
}
|
2001
|
+
}
|
2002
|
+
|
2003
|
+
const MVP = player['★']
|
2004
|
+
delete player['★']
|
2005
|
+
if(MVP === '') {
|
2006
|
+
player.MVP = 0
|
2007
|
+
}
|
2008
|
+
else if(MVP === '★') {
|
2009
|
+
player.MVP = 1
|
2010
|
+
}
|
2011
|
+
else if(MVP.startsWith('★')) {
|
2012
|
+
player.MVP = parseInt(MVP.replaceAll('★', ''))
|
2013
|
+
}
|
2014
|
+
else {
|
2015
|
+
//error
|
2016
|
+
console.log(MVP)
|
2017
|
+
}
|
2018
|
+
|
2019
|
+
player.HSP = player.HSP === '' ? null : parseInt(player.HSP.replaceAll('%', ''))
|
2020
|
+
|
2021
|
+
const _player = {
|
2022
|
+
...player,
|
2023
|
+
name: player['Player Name'].name,
|
2024
|
+
link: player['Player Name'].link,
|
2025
|
+
customURL: player['Player Name'].customURL,
|
2026
|
+
steamID: SteamUser.miniprofile2SteamID64(player['Player Name'].miniprofile),
|
2027
|
+
miniprofile: player['Player Name'].miniprofile,
|
2028
|
+
isMe: player['Player Name'].miniprofile === myMiniProfile,
|
2029
|
+
avatarHash: player['Player Name'].avatarHash,
|
2030
|
+
}
|
2031
|
+
delete _player['Player Name']
|
2032
|
+
|
2033
|
+
players.push(_player)
|
2034
|
+
}
|
2035
|
+
|
2036
|
+
const myTeam = players.find(p => p.isMe)?.team
|
2037
|
+
myTeam && players.forEach(p => p.isTeammate = p.team === myTeam && !p.isMe)
|
2038
|
+
|
2039
|
+
const matchIDs = [matchInfo.map, matchInfo.time, matchInfo.waitTime, matchInfo.duration]
|
2040
|
+
const nonHashMatchID = matchIDs.join('').replaceAll(/[^a-zA-Z0-9]/gi, '')
|
2041
|
+
const matchID = sha256(nonHashMatchID).toString()
|
2042
|
+
|
2043
|
+
matches.push({
|
2044
|
+
id: matchID,
|
2045
|
+
matchInfo,
|
2046
|
+
players,
|
2047
|
+
})
|
2048
|
+
})
|
2049
|
+
|
2050
|
+
return matches
|
2051
|
+
}
|
2052
|
+
|
2053
|
+
async getFullHistoryMatches({
|
2054
|
+
matchHistoryTypes = [],
|
2055
|
+
cbOnMatch = null,
|
2056
|
+
cbOnMatches = null,
|
2057
|
+
maxPage = null,
|
2058
|
+
Started_playing_CS_GO = null,
|
2059
|
+
shouldStop = function ({
|
2060
|
+
maxPage,
|
2061
|
+
currentPage,
|
2062
|
+
continue_token,
|
2063
|
+
continue_text,
|
2064
|
+
matchHistoryType,
|
2065
|
+
}) {
|
2066
|
+
if(maxPage === null) {
|
2067
|
+
return false
|
2068
|
+
}
|
2069
|
+
else {
|
2070
|
+
return currentPage > maxPage
|
2071
|
+
}
|
2072
|
+
}
|
2073
|
+
}) {
|
2074
|
+
|
2075
|
+
if(!Array.isArray(matchHistoryTypes)) {
|
2076
|
+
matchHistoryTypes = [matchHistoryTypes]
|
2077
|
+
}
|
2078
|
+
|
2079
|
+
const results = {}
|
2080
|
+
if(maxPage === null && Started_playing_CS_GO === null) {
|
2081
|
+
Started_playing_CS_GO = (await this.getPersonalGameDataAccountInformation())?.Started_playing_CS_GO
|
2082
|
+
}
|
2083
|
+
if(!Started_playing_CS_GO || !(Started_playing_CS_GO = moment(Started_playing_CS_GO.replace('GMT', '+00'), `YYYY-MM-DD HH:mm:ss Z`)).isValid()) {
|
2084
|
+
Started_playing_CS_GO = null
|
2085
|
+
}
|
2086
|
+
for (const matchHistoryType of matchHistoryTypes) {
|
2087
|
+
results[matchHistoryType] = await this._getFullHistoryMatches({
|
2088
|
+
matchHistoryType,
|
2089
|
+
cbOnMatch,
|
2090
|
+
cbOnMatches,
|
2091
|
+
maxPage,
|
2092
|
+
Started_playing_CS_GO,
|
2093
|
+
shouldStop
|
2094
|
+
})
|
2095
|
+
}
|
2096
|
+
return results
|
2097
|
+
}
|
2098
|
+
|
2099
|
+
async _getFullHistoryMatches({
|
2100
|
+
matchHistoryType = '',
|
2101
|
+
cbOnMatch,
|
2102
|
+
cbOnMatches,
|
2103
|
+
maxPage,
|
2104
|
+
Started_playing_CS_GO,
|
2105
|
+
shouldStop
|
2106
|
+
}) {
|
2107
|
+
|
2108
|
+
let result = null,
|
2109
|
+
page = 0,
|
2110
|
+
stop = false
|
2111
|
+
const matches = []
|
2112
|
+
|
2113
|
+
do {
|
2114
|
+
result = await (page++ ? this._getHistoryMatches(matchHistoryType, result?.continue_token) : this.getMatchHistory_initial(matchHistoryType))
|
2115
|
+
stop = shouldStop({
|
2116
|
+
maxPage,
|
2117
|
+
currentPage: page,
|
2118
|
+
continue_token: result.continue_token,
|
2119
|
+
continue_text: result.continue_text,
|
2120
|
+
matchHistoryType,
|
2121
|
+
})
|
2122
|
+
|
2123
|
+
if(result.continue_text && Started_playing_CS_GO && moment(result.continue_text, 'YYYY-MM-DD').isBefore(Started_playing_CS_GO)) {
|
2124
|
+
stop = true
|
2125
|
+
}
|
2126
|
+
|
2127
|
+
if(!result.continue_token) {
|
2128
|
+
stop = true
|
2129
|
+
}
|
2130
|
+
|
2131
|
+
Array.isArray(result.matches) && result.matches.length && typeof cbOnMatches === 'function' && await cbOnMatches(result.matches)
|
2132
|
+
|
2133
|
+
for (const match of result.matches) {
|
2134
|
+
if(match.players.length) {
|
2135
|
+
matches.push(match)
|
2136
|
+
typeof cbOnMatch === 'function' && await cbOnMatch(match)
|
2137
|
+
}
|
2138
|
+
}
|
2139
|
+
} while (!stop)
|
2140
|
+
|
2141
|
+
return matches
|
2142
|
+
}
|
2143
|
+
|
2144
|
+
//{ success: 1 } means success
|
2145
|
+
//{ success: 2 }
|
2146
|
+
async followUser(steamID) {
|
2147
|
+
const {data} = await this._httpRequest({
|
2148
|
+
url: `${this.getSteamUserProfileURL(steamID)}/followuser/`,
|
2149
|
+
method: 'POST',
|
2150
|
+
})
|
2151
|
+
|
2152
|
+
return data
|
2153
|
+
}
|
2154
|
+
|
2155
|
+
//from profile
|
2156
|
+
async unfollowUser(steamID) {
|
2157
|
+
const {data} = await this._httpRequest({
|
2158
|
+
url: `${this.getSteamUserProfileURL(steamID)}/unfollowuser/`,
|
2159
|
+
method: 'POST',
|
2160
|
+
})
|
2161
|
+
|
2162
|
+
return data
|
2163
|
+
}
|
2164
|
+
|
2165
|
+
//from following manager
|
2166
|
+
async unfollowUsers(steamIDs) {
|
2167
|
+
const formData = new URLSearchParams()
|
2168
|
+
formData.append('steamid', this.getSteamidUser())
|
2169
|
+
formData.append('ajax', '1')
|
2170
|
+
formData.append('action', 'unfollow')
|
2171
|
+
steamIDs.forEach(steamID => {
|
2172
|
+
formData.append('steamids[]', steamID.toString())
|
2173
|
+
})
|
2174
|
+
|
2175
|
+
const {data} = await this._httpRequestAjax({
|
2176
|
+
url: `${this.getMySteamUserProfileURL()}/friends/action`,
|
2177
|
+
method: 'POST',
|
2178
|
+
data: formData,
|
2179
|
+
})
|
2180
|
+
|
2181
|
+
return data
|
2182
|
+
}
|
2183
|
+
|
2184
|
+
//from following manager
|
2185
|
+
async unfollowAllFollowUsers() {
|
2186
|
+
const friends = await this.getMyFollowingPlayersList()
|
2187
|
+
return await this.unfollowUsers(friends.map(r => r.steamId))
|
2188
|
+
}
|
2189
|
+
|
2190
|
+
//true, false boolean
|
2191
|
+
async blockCommunicationUser(steamID) {
|
2192
|
+
const {data} = await this._httpRequest({
|
2193
|
+
url: `actions/BlockUserAjax`,
|
2194
|
+
data: {
|
2195
|
+
steamid: steamID,
|
2196
|
+
block: 1,
|
2197
|
+
},
|
2198
|
+
method: 'POST',
|
2199
|
+
})
|
2200
|
+
|
2201
|
+
return data
|
2202
|
+
}
|
2203
|
+
|
2204
|
+
//true, false boolean
|
2205
|
+
async unblockCommunicationUser(steamID) {
|
2206
|
+
const {data} = await this._httpRequest({
|
2207
|
+
url: `actions/BlockUserAjax`,
|
2208
|
+
data: {
|
2209
|
+
steamid: steamID,
|
2210
|
+
block: 0,
|
2211
|
+
},
|
2212
|
+
method: 'POST',
|
2213
|
+
})
|
2214
|
+
|
2215
|
+
return data
|
2216
|
+
}
|
2217
|
+
|
2218
|
+
|
2219
|
+
//{ invited: [ '76561199277912057' ], success: 1 }
|
2220
|
+
async addFriendUser(steamID) {
|
2221
|
+
const {data} = await this._httpRequest({
|
2222
|
+
url: `actions/AddFriendAjax`,
|
2223
|
+
data: {
|
2224
|
+
steamid: steamID,
|
2225
|
+
accept_invite: 0,
|
2226
|
+
},
|
2227
|
+
method: 'POST',
|
2228
|
+
})
|
2229
|
+
|
2230
|
+
return data
|
2231
|
+
}
|
2232
|
+
|
2233
|
+
|
2234
|
+
//true, false boolean
|
2235
|
+
async removeFriend(steamID) {
|
2236
|
+
const {data} = await this._httpRequest({
|
2237
|
+
url: `actions/RemoveFriendAjax`,
|
2238
|
+
data: {
|
2239
|
+
steamid: steamID
|
2240
|
+
},
|
2241
|
+
method: 'POST',
|
2242
|
+
})
|
2243
|
+
return data
|
2244
|
+
}
|
2245
|
+
|
2246
|
+
async acceptFriendRequest(steamID) {
|
2247
|
+
const {data} = await this._httpRequest({
|
2248
|
+
url: `${this.getMySteamUserProfileURL()}/friends/action`,
|
2249
|
+
data: {
|
2250
|
+
steamid: this._steamid_user,
|
2251
|
+
ajax: 1,
|
2252
|
+
action: 'accept',
|
2253
|
+
'steamids[]': steamID,
|
2254
|
+
},
|
2255
|
+
method: 'POST',
|
2256
|
+
})
|
2257
|
+
return data
|
2258
|
+
const resultExample = {
|
2259
|
+
success: 2,
|
2260
|
+
rgCounts: {
|
2261
|
+
cFriendsPending: 11,
|
2262
|
+
cFriendsBlocked: 1,
|
2263
|
+
cFollowing: 179,
|
2264
|
+
cGroupsPending: 0,
|
2265
|
+
cFriends: 183,
|
2266
|
+
cGroups: 1,
|
2267
|
+
success: 1
|
2268
|
+
}
|
2269
|
+
}
|
2270
|
+
}
|
2271
|
+
|
2272
|
+
async cancelAddFriendUser(steamID) {
|
2273
|
+
return await this.removeFriend(steamID)
|
2274
|
+
}
|
2275
|
+
|
2276
|
+
async ignoreFriendRequest(steamID) {
|
2277
|
+
const {data} = await this._httpRequestAjax({
|
2278
|
+
url: `actions/IgnoreFriendInviteAjax`,
|
2279
|
+
data: {
|
2280
|
+
steamid: steamID,
|
2281
|
+
},
|
2282
|
+
method: 'POST',
|
2283
|
+
})
|
2284
|
+
return data
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
//{"success":1,"nickname":"new nickname"}
|
2288
|
+
async setNickname(steamID, nickname) {
|
2289
|
+
const {data} = await this._httpRequestAjax({
|
2290
|
+
url: `${this.getSteamUserProfileURL(steamID)}/ajaxsetnickname/`,
|
2291
|
+
data: {
|
2292
|
+
nickname: nickname,
|
2293
|
+
},
|
2294
|
+
method: 'POST',
|
2295
|
+
})
|
2296
|
+
return data
|
2297
|
+
}
|
2298
|
+
|
2299
|
+
//{ success: 1, nickname: '' }
|
2300
|
+
async removeNickname(steamID) {
|
2301
|
+
return await this.setNickname(steamID, '')
|
2302
|
+
}
|
2303
|
+
|
2304
|
+
|
2305
|
+
async getNameHistory(steamID = this.getSteamidUser()) {
|
2306
|
+
const {data} = await this._httpRequestAjax({
|
2307
|
+
url: `${this.getSteamUserProfileURL(steamID)}/ajaxaliases/`,
|
2308
|
+
method: 'POST',
|
2309
|
+
})
|
2310
|
+
return data
|
2311
|
+
const resultExample = [{
|
2312
|
+
newname: 'Natri',
|
2313
|
+
timechanged: '9 Aug @ 6:26am'
|
2314
|
+
}, {
|
2315
|
+
newname: 'Natri 1',
|
2316
|
+
timechanged: '9 Aug @ 6:26am'
|
2317
|
+
}]
|
2318
|
+
}
|
2319
|
+
|
2320
|
+
getPreviousAliases = this.getNameHistory
|
2321
|
+
|
2322
|
+
async clearPreviousAliases() {
|
2323
|
+
const {data} = await this._httpRequestAjax({
|
2324
|
+
url: `${this.getMySteamUserProfileURL()}/ajaxclearaliashistory/`,
|
2325
|
+
method: 'POST',
|
2326
|
+
})
|
2327
|
+
return data
|
2328
|
+
}
|
2329
|
+
|
2330
|
+
async setupProfile() {
|
2331
|
+
const profile = await this._httpRequest(`/edit?welcomed=1`)
|
2332
|
+
if(!profile.data) {
|
2333
|
+
return false
|
2334
|
+
}
|
2335
|
+
const $ = profile._$()
|
2336
|
+
return $('title').text() == 'Steam Community :: Edit Profile'
|
2337
|
+
}
|
2338
|
+
|
2339
|
+
async editMyProfile({
|
2340
|
+
personaName = null,
|
2341
|
+
realName = null,
|
2342
|
+
customURL = null,
|
2343
|
+
country = null,
|
2344
|
+
summary = null,
|
2345
|
+
hide_profile_awards = null
|
2346
|
+
}) {
|
2347
|
+
const existProfile = await this._httpRequest(`/my/edit/info`)
|
2348
|
+
if(!existProfile.data) {
|
2349
|
+
return
|
2350
|
+
}
|
2351
|
+
const $ = existProfile._$()
|
2352
|
+
const profileEdit = $('#profile_edit_config').data('profile-edit')
|
2353
|
+
if(!profileEdit) {
|
2354
|
+
return
|
2355
|
+
}
|
2356
|
+
|
2357
|
+
const {data} = await this._httpRequestAjax({
|
2358
|
+
url: `${this.getMySteamUserProfileURL()}/edit/`,
|
2359
|
+
method: 'POST',
|
2360
|
+
data: {
|
2361
|
+
type: 'profileSave',
|
2362
|
+
weblink_1_title: '',
|
2363
|
+
weblink_1_url: '',
|
2364
|
+
weblink_2_title: '',
|
2365
|
+
weblink_2_url: '',
|
2366
|
+
weblink_3_title: '',
|
2367
|
+
weblink_3_url: '',
|
2368
|
+
personaName: personaName === null ? profileEdit.strPersonaName : personaName,
|
2369
|
+
real_name: realName === null ? profileEdit.strRealName : realName,
|
2370
|
+
customURL: customURL === null ? profileEdit.strCustomURL : customURL,
|
2371
|
+
country: country === null ? profileEdit.LocationData.locCountryCode : country,
|
2372
|
+
state: profileEdit.LocationData.locStateCode,
|
2373
|
+
city: profileEdit.LocationData.locCityCode,
|
2374
|
+
summary: summary || profileEdit.strSummary,
|
2375
|
+
hide_profile_awards: hide_profile_awards === null ? profileEdit.ProfilePreferences.hide_profile_awards : (hide_profile_awards ? '1' : '0'),
|
2376
|
+
json: 1,
|
2377
|
+
},
|
2378
|
+
headers: {
|
2379
|
+
'Content-Type': 'multipart/form-data',
|
2380
|
+
},
|
2381
|
+
})
|
2382
|
+
return data
|
2383
|
+
const successExample = {
|
2384
|
+
success: 1,
|
2385
|
+
errmsg: ''
|
2386
|
+
}
|
2387
|
+
const errorExample = {
|
2388
|
+
success: 2,
|
2389
|
+
errmsg: 'The profile URL specified is already in use<br />Bad location specified.<br />'
|
2390
|
+
}
|
2391
|
+
}
|
2392
|
+
|
2393
|
+
static _formatPrivacySettings2String(privacySettings) {//number to string
|
2394
|
+
const Privacy = privacySettings?.data?.Privacy || privacySettings?.Privacy
|
2395
|
+
if(!Privacy) {
|
2396
|
+
return
|
2397
|
+
}
|
2398
|
+
|
2399
|
+
const _Privacy = Object.entries(Privacy.PrivacySettings).reduce((previousValue, [field, setting]) => ({
|
2400
|
+
...previousValue,
|
2401
|
+
[field]: Object.entries(SteamUser._EPrivacyState).find(([, value]) => value == setting)[0]
|
2402
|
+
}), {})
|
2403
|
+
|
2404
|
+
_Privacy.eCommentPermission = Object.entries(SteamUser._ECommentPrivacyState).find(([, value]) => value == Privacy.eCommentPermission)[0]
|
2405
|
+
|
2406
|
+
return {
|
2407
|
+
profile: _Privacy.PrivacyProfile,
|
2408
|
+
inventory: _Privacy.PrivacyInventory,
|
2409
|
+
inventoryGifts: _Privacy.PrivacyInventoryGifts,
|
2410
|
+
gameDetails: _Privacy.PrivacyOwnedGames,
|
2411
|
+
playtime: _Privacy.PrivacyPlaytime,
|
2412
|
+
friendsList: _Privacy.PrivacyFriendsList,
|
2413
|
+
comment: _Privacy.eCommentPermission
|
2414
|
+
}
|
2415
|
+
}
|
2416
|
+
|
2417
|
+
static _formatPrivacySettings2Value(privacySettings) {//string to number
|
2418
|
+
const _Privacy = Object.entries(privacySettings).reduce((previousValue, [key, value]) => {
|
2419
|
+
const mapping = (key === 'comment' ? SteamUser._ECommentPrivacyState : SteamUser._EPrivacyState)
|
2420
|
+
//value: string or number
|
2421
|
+
let newValue
|
2422
|
+
if(Object.hasOwn(mapping, value)) {
|
2423
|
+
newValue = mapping[value]
|
2424
|
+
}
|
2425
|
+
else if(!isNaN(parseInt(value))) {
|
2426
|
+
newValue = value
|
2427
|
+
}
|
2428
|
+
else {
|
2429
|
+
throw new Error(`Invalid privacySettings value: ${value}`)
|
2430
|
+
}
|
2431
|
+
|
2432
|
+
return {
|
2433
|
+
...previousValue,
|
2434
|
+
[key]: newValue
|
2435
|
+
}
|
2436
|
+
}, {})
|
2437
|
+
|
2438
|
+
return {
|
2439
|
+
PrivacySettings: {
|
2440
|
+
PrivacyProfile: _Privacy.profile,
|
2441
|
+
PrivacyInventory: _Privacy.inventory,
|
2442
|
+
PrivacyInventoryGifts: _Privacy.inventoryGifts,
|
2443
|
+
PrivacyOwnedGames: _Privacy.gameDetails,
|
2444
|
+
PrivacyPlaytime: _Privacy.playtime,
|
2445
|
+
PrivacyFriendsList: _Privacy.friendsList,
|
2446
|
+
},
|
2447
|
+
eCommentPermission: _Privacy.comment,
|
2448
|
+
}
|
2449
|
+
}
|
2450
|
+
|
2451
|
+
async getPrivacySettings() {
|
2452
|
+
const result = await this._httpRequest({
|
2453
|
+
url: `${this.getMySteamUserProfileURL()}/edit/settings`,
|
2454
|
+
})
|
2455
|
+
|
2456
|
+
if(!result.data) {
|
2457
|
+
return
|
2458
|
+
}
|
2459
|
+
|
2460
|
+
const $ = result._$()
|
2461
|
+
const existingSettings = $('#profile_edit_config').data('profile-edit')
|
2462
|
+
return SteamUser._formatPrivacySettings2String(existingSettings)
|
2463
|
+
|
2464
|
+
const successExample = {
|
2465
|
+
strPersonaName: 'Birdman',
|
2466
|
+
strCustomURL: '',
|
2467
|
+
strRealName: '',
|
2468
|
+
strSummary: 'No information given.',
|
2469
|
+
strAvatarHash: '33915da4fb4ca63a17d6841876fd18d7e30f9585',
|
2470
|
+
rtPersonaNameBannedUntil: 0,
|
2471
|
+
rtProfileSummaryBannedUntil: 0,
|
2472
|
+
rtAvatarBannedUntil: 0,
|
2473
|
+
LocationData: {
|
2474
|
+
locCountry: '',
|
2475
|
+
locCountryCode: '',
|
2476
|
+
locState: '',
|
2477
|
+
locStateCode: '',
|
2478
|
+
locCity: '',
|
2479
|
+
locCityCode: ''
|
2480
|
+
},
|
2481
|
+
ActiveTheme: {
|
2482
|
+
theme_id: '',
|
2483
|
+
title: '#ProfileTheme_Default'
|
2484
|
+
},
|
2485
|
+
ProfilePreferences: {
|
2486
|
+
hide_profile_awards: 0
|
2487
|
+
},
|
2488
|
+
rgAvailableThemes: [{
|
2489
|
+
theme_id: '',
|
2490
|
+
title: '#ProfileTheme_Default'
|
2491
|
+
}, {
|
2492
|
+
theme_id: 'Summer',
|
2493
|
+
title: '#ProfileTheme_Summer'
|
2494
|
+
}, {
|
2495
|
+
theme_id: 'Midnight',
|
2496
|
+
title: '#ProfileTheme_Midnight'
|
2497
|
+
}, {
|
2498
|
+
theme_id: 'Steel',
|
2499
|
+
title: '#ProfileTheme_Steel'
|
2500
|
+
}, {
|
2501
|
+
theme_id: 'Cosmic',
|
2502
|
+
title: '#ProfileTheme_Cosmic'
|
2503
|
+
}, {
|
2504
|
+
theme_id: 'DarkMode',
|
2505
|
+
title: '#ProfileTheme_DarkMode'
|
2506
|
+
}],
|
2507
|
+
rgGoldenProfileData: [{
|
2508
|
+
appid: 1017190,
|
2509
|
+
css_url: 'https://community.cloudflare.steamstatic.com/public/css/promo/lny2019/goldenprofile.css?v=MNHyDjqMV1IZ&l=english&_cdn=cloudflare',
|
2510
|
+
frame_url: null,
|
2511
|
+
miniprofile_background: null,
|
2512
|
+
miniprofile_movie: null
|
2513
|
+
}, {
|
2514
|
+
appid: 1263950,
|
2515
|
+
css_url: 'https://community.cloudflare.steamstatic.com/public/css/promo/rewardsseason1/goldenprofile.css?v=.xVjuuVRtFd6T&_cdn=cloudflare',
|
2516
|
+
frame_url: 'https://cdn.cloudflare.steamstatic.com/steamcommunity/public/assets/rewardsseason1/goldenprofile/presige_frame_anim.png?v=2',
|
2517
|
+
miniprofile_background: 'https://cdn.cloudflare.steamstatic.com/steamcommunity/public/assets/rewardsseason1/goldenprofile/gp_mini_profile_still.png?v=2',
|
2518
|
+
miniprofile_movie: {
|
2519
|
+
'video/webm': 'https://cdn.cloudflare.steamstatic.com/steamcommunity/public/assets/rewardsseason1/goldenprofile/summer2020_golden_mini_profile_background.webm?v=2'
|
2520
|
+
}
|
2521
|
+
},],
|
2522
|
+
Privacy: {
|
2523
|
+
PrivacySettings: {
|
2524
|
+
PrivacyProfile: 'Public',//Your community profile includes your profile summary, friends list, badges, Steam Level, showcases, comments, and group membership.
|
2525
|
+
PrivacyInventory: 'Public',//This controls who can see your list of friends on your Steam Community profile.
|
2526
|
+
PrivacyInventoryGifts: 'Public',//Always keep Steam Gifts private even if users can see my inventory.
|
2527
|
+
PrivacyOwnedGames: 'Public',//Game details
|
2528
|
+
PrivacyPlaytime: 'Public',//Always keep my total playtime private even if users can see my game details.
|
2529
|
+
PrivacyFriendsList: 'Public'//This controls who can see your list of friends on your Steam Community profile.
|
2530
|
+
},
|
2531
|
+
eCommentPermission: 'Public'
|
2532
|
+
},
|
2533
|
+
webapi_token: '38a169cea9b4402fe1a3db093a0f0e1b'
|
2534
|
+
}
|
2535
|
+
}
|
2536
|
+
|
2537
|
+
async updatePrivacySettings(privacySettings) {
|
2538
|
+
let existingSettings = {}
|
2539
|
+
//get missing setting
|
2540
|
+
if(Object.keys(PrivacySettings).some(key => !Object.hasOwn(privacySettings, key))) {
|
2541
|
+
existingSettings = await this.getPrivacySettings()
|
2542
|
+
if(existingSettings) {
|
2543
|
+
const isEqual = _.isEqual(_.pick(existingSettings, Object.keys(privacySettings)), privacySettings)
|
2544
|
+
if(isEqual) {
|
2545
|
+
//nothing to update
|
2546
|
+
return
|
2547
|
+
}
|
2548
|
+
}
|
2549
|
+
else {
|
2550
|
+
//cant get current setting
|
2551
|
+
return
|
2552
|
+
}
|
2553
|
+
}
|
2554
|
+
|
2555
|
+
const privacy = {...existingSettings, ...privacySettings}
|
2556
|
+
const privacyValue = SteamUser._formatPrivacySettings2Value(privacy)
|
2557
|
+
|
2558
|
+
const {
|
2559
|
+
data,
|
2560
|
+
} = await this._httpRequestAjax({
|
2561
|
+
url: `${this.getMySteamUserProfileURL()}/ajaxsetprivacy`,
|
2562
|
+
method: 'POST',
|
2563
|
+
data: {
|
2564
|
+
Privacy: JSON.stringify(privacyValue.PrivacySettings),
|
2565
|
+
eCommentPermission: privacyValue.eCommentPermission
|
2566
|
+
}
|
2567
|
+
})
|
2568
|
+
|
2569
|
+
if(!data || data === 'null') {
|
2570
|
+
return
|
2571
|
+
}
|
2572
|
+
|
2573
|
+
return SteamUser._formatPrivacySettings2String(data)
|
2574
|
+
}
|
2575
|
+
|
2576
|
+
async publicPrivacySettings() {
|
2577
|
+
return await this.updatePrivacySettings({
|
2578
|
+
profile: EPrivacyState.Public,
|
2579
|
+
inventory: EPrivacyState.Public,
|
2580
|
+
inventoryGifts: EPrivacyState.Public,
|
2581
|
+
gameDetails: EPrivacyState.Public,
|
2582
|
+
playtime: EPrivacyState.Public,
|
2583
|
+
friendsList: EPrivacyState.Public,
|
2584
|
+
comment: EPrivacyState.Public
|
2585
|
+
})
|
2586
|
+
}
|
2587
|
+
|
2588
|
+
async privatePrivacySettings() {
|
2589
|
+
return await this.updatePrivacySettings({
|
2590
|
+
profile: EPrivacyState.Private,
|
2591
|
+
inventory: EPrivacyState.Private,
|
2592
|
+
inventoryGifts: EPrivacyState.Private,
|
2593
|
+
gameDetails: EPrivacyState.Private,
|
2594
|
+
playtime: EPrivacyState.Private,
|
2595
|
+
friendsList: EPrivacyState.Private,
|
2596
|
+
comment: EPrivacyState.Private
|
2597
|
+
})
|
2598
|
+
}
|
2599
|
+
|
2600
|
+
async postComment(steamID, message) {
|
2601
|
+
const {data} = await this._httpRequestAjax({
|
2602
|
+
url: `comment/Profile/post/${steamID}/-1/`,
|
2603
|
+
method: 'POST',
|
2604
|
+
data: {
|
2605
|
+
comment: message,
|
2606
|
+
count: 6,
|
2607
|
+
feature2: -1,
|
2608
|
+
}
|
2609
|
+
})
|
2610
|
+
if(!data?.comments_html) {
|
2611
|
+
return
|
2612
|
+
}
|
2613
|
+
|
2614
|
+
data.comments = this._parseComments(data.comments_html)
|
2615
|
+
data.comment = data.comments.find(c => c.timestamp == data.timelastpost)
|
2616
|
+
return data
|
2617
|
+
|
2618
|
+
const errorExample = {
|
2619
|
+
success: false,
|
2620
|
+
error: 'You\'ve been posting too frequently, and can\'t make another post right now'
|
2621
|
+
}
|
2622
|
+
const successExample = {
|
2623
|
+
success: true,
|
2624
|
+
name: 'Profile_76561199277912057',
|
2625
|
+
start: 0,
|
2626
|
+
pagesize: '6',
|
2627
|
+
total_count: 5,
|
2628
|
+
upvotes: 0,
|
2629
|
+
has_upvoted: 0,
|
2630
|
+
comments_html: '\t\t\r\n\t\r\n\t<div data-panel="{"flow-children":"row","type":"PanelGroup"}" class="commentthread_comment responsive_body_text " id="comment_3455968685021221554" style="">\r\n\t\t\t\t<div class="commentthread_comment_avatar playerAvatar online">\r\n\t\t\t\t\t\t<a href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t\t\t\t\t<img src="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg" srcset="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg 1x, https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64_medium.jpg 2x">\t\t\t\t\t\t\t</a>\r\n\t\t</div>\r\n\t\t<div class="commentthread_comment_content">\r\n\t\t\t<div data-panel="{"flow-children":"row"}" class="commentthread_comment_author">\r\n\t\t\t\t<a class="hoverunderline commentthread_author_link" href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t<bdi>Natri</bdi></a>\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t<span class="commentthread_comment_timestamp" title="9 August, 2022 @ 6:36:13 am +07" data-timestamp="1660001773">\r\n\t\t\t\t\tJust now \r\n\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t<div class="commentthread_comment_actions" >\r\n\t\t\t\t\t<a class="actionlink" data-tooltip-text="Delete" href="javascript:CCommentThread.DeleteComment( \'Profile_76561199277912057\', \'3455968685021221554\' );"><img src="https://community.cloudflare.steamstatic.com/public/images/skin_1/notification_icon_trash_bright.png?v=1" ></a>\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class="commentthread_comment_text" id="comment_content_3455968685021221554">\r\n\t\t\t\tddddddd\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\r\n\t\r\n\t<div data-panel="{"flow-children":"row","type":"PanelGroup"}" class="commentthread_comment responsive_body_text " id="comment_3455968685021217640" style="">\r\n\t\t\t\t<div class="commentthread_comment_avatar playerAvatar online">\r\n\t\t\t\t\t\t<a href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t\t\t\t\t<img src="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg" srcset="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg 1x, https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64_medium.jpg 2x">\t\t\t\t\t\t\t</a>\r\n\t\t</div>\r\n\t\t<div class="commentthread_comment_content">\r\n\t\t\t<div data-panel="{"flow-children":"row"}" class="commentthread_comment_author">\r\n\t\t\t\t<a class="hoverunderline commentthread_author_link" href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t<bdi>Natri</bdi></a>\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t<span class="commentthread_comment_timestamp" title="9 August, 2022 @ 6:34:41 am +07" data-timestamp="1660001681">\r\n\t\t\t\t\tJust now \r\n\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t<div class="commentthread_comment_actions" >\r\n\t\t\t\t\t<a class="actionlink" data-tooltip-text="Delete" href="javascript:CCommentThread.DeleteComment( \'Profile_76561199277912057\', \'3455968685021217640\' );"><img src="https://community.cloudflare.steamstatic.com/public/images/skin_1/notification_icon_trash_bright.png?v=1" ></a>\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class="commentthread_comment_text" id="comment_content_3455968685021217640">\r\n\t\t\t\tddddddd\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\r\n\t\r\n\t<div data-panel="{"flow-children":"row","type":"PanelGroup"}" class="commentthread_comment responsive_body_text " id="comment_3455968685021214294" style="">\r\n\t\t\t\t<div class="commentthread_comment_avatar playerAvatar online">\r\n\t\t\t\t\t\t<a href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t\t\t\t\t<img src="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg" srcset="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg 1x, https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64_medium.jpg 2x">\t\t\t\t\t\t\t</a>\r\n\t\t</div>\r\n\t\t<div class="commentthread_comment_content">\r\n\t\t\t<div data-panel="{"flow-children":"row"}" class="commentthread_comment_author">\r\n\t\t\t\t<a class="hoverunderline commentthread_author_link" href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t<bdi>Natri</bdi></a>\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t<span class="commentthread_comment_timestamp" title="9 August, 2022 @ 6:33:22 am +07" data-timestamp="1660001602">\r\n\t\t\t\t\t2 minutes ago \r\n\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t<div class="commentthread_comment_actions" >\r\n\t\t\t\t\t<a class="actionlink" data-tooltip-text="Delete" href="javascript:CCommentThread.DeleteComment( \'Profile_76561199277912057\', \'3455968685021214294\' );"><img src="https://community.cloudflare.steamstatic.com/public/images/skin_1/notification_icon_trash_bright.png?v=1" ></a>\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class="commentthread_comment_text" id="comment_content_3455968685021214294">\r\n\t\t\t\tddddddd\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\r\n\t\r\n\t<div data-panel="{"flow-children":"row","type":"PanelGroup"}" class="commentthread_comment responsive_body_text " id="comment_3455968685021213633" style="">\r\n\t\t\t\t<div class="commentthread_comment_avatar playerAvatar online">\r\n\t\t\t\t\t\t<a href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t\t\t\t\t<img src="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg" srcset="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg 1x, https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64_medium.jpg 2x">\t\t\t\t\t\t\t</a>\r\n\t\t</div>\r\n\t\t<div class="commentthread_comment_content">\r\n\t\t\t<div data-panel="{"flow-children":"row"}" class="commentthread_comment_author">\r\n\t\t\t\t<a class="hoverunderline commentthread_author_link" href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t<bdi>Natri</bdi></a>\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t<span class="commentthread_comment_timestamp" title="9 August, 2022 @ 6:33:06 am +07" data-timestamp="1660001586">\r\n\t\t\t\t\t3 minutes ago \r\n\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t<div class="commentthread_comment_actions" >\r\n\t\t\t\t\t<a class="actionlink" data-tooltip-text="Delete" href="javascript:CCommentThread.DeleteComment( \'Profile_76561199277912057\', \'3455968685021213633\' );"><img src="https://community.cloudflare.steamstatic.com/public/images/skin_1/notification_icon_trash_bright.png?v=1" ></a>\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class="commentthread_comment_text" id="comment_content_3455968685021213633">\r\n\t\t\t\tddddddd\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\r\n\t\r\n\t<div data-panel="{"flow-children":"row","type":"PanelGroup"}" class="commentthread_comment responsive_body_text " id="comment_3455968685021212374" style="">\r\n\t\t\t\t<div class="commentthread_comment_avatar playerAvatar online">\r\n\t\t\t\t\t\t<a href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t\t\t\t\t<img src="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg" srcset="https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg 1x, https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64_medium.jpg 2x">\t\t\t\t\t\t\t</a>\r\n\t\t</div>\r\n\t\t<div class="commentthread_comment_content">\r\n\t\t\t<div data-panel="{"flow-children":"row"}" class="commentthread_comment_author">\r\n\t\t\t\t<a class="hoverunderline commentthread_author_link" href="https://steamcommunity.com/id/natri99" data-miniprofile="1080136620">\r\n\t\t\t\t\t<bdi>Natri</bdi></a>\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t<span class="commentthread_comment_timestamp" title="9 August, 2022 @ 6:32:37 am +07" data-timestamp="1660001557">\r\n\t\t\t\t\t3 minutes ago \r\n\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t<div class="commentthread_comment_actions" >\r\n\t\t\t\t\t<a class="actionlink" data-tooltip-text="Delete" href="javascript:CCommentThread.DeleteComment( \'Profile_76561199277912057\', \'3455968685021212374\' );"><img src="https://community.cloudflare.steamstatic.com/public/images/skin_1/notification_icon_trash_bright.png?v=1" ></a>\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class="commentthread_comment_text" id="comment_content_3455968685021212374">\r\n\t\t\t\tddddddd\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t</div>\r\n',
|
2631
|
+
timelastpost: 1660001773,
|
2632
|
+
comments: [{
|
2633
|
+
id: '3455968685021221554',
|
2634
|
+
content: 'ddddddd',
|
2635
|
+
timestamp: 1660001773,
|
2636
|
+
author: {
|
2637
|
+
steamID: '76561199040402348',
|
2638
|
+
profileURL: 'https://steamcommunity.com/id/natri99',
|
2639
|
+
miniprofile: 1080136620,
|
2640
|
+
name: 'Natri',
|
2641
|
+
avatar: 'https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg'
|
2642
|
+
}
|
2643
|
+
},],
|
2644
|
+
comment: {
|
2645
|
+
id: '3455968685021221554',
|
2646
|
+
content: 'ddddddd',
|
2647
|
+
timestamp: 1660001773,
|
2648
|
+
author: {
|
2649
|
+
steamID: '76561199040402348',
|
2650
|
+
profileURL: 'https://steamcommunity.com/id/natri99',
|
2651
|
+
miniprofile: 1080136620,
|
2652
|
+
name: 'Natri',
|
2653
|
+
avatar: 'https://avatars.cloudflare.steamstatic.com/834966fea6a0a8a3b7011db7f96d38b51ee0ba64.jpg'
|
2654
|
+
}
|
2655
|
+
}
|
2656
|
+
}
|
2657
|
+
}
|
2658
|
+
|
2659
|
+
async deleteComment(steamID, gidcomment) {
|
2660
|
+
const {data} = await this._httpRequestAjax({
|
2661
|
+
url: `comment/Profile/delete/${steamID}/-1/`,
|
2662
|
+
method: 'POST',
|
2663
|
+
data: {
|
2664
|
+
gidcomment: gidcomment,
|
2665
|
+
start: 0,
|
2666
|
+
count: 6,
|
2667
|
+
feature2: -1,
|
2668
|
+
}
|
2669
|
+
})
|
2670
|
+
return data
|
2671
|
+
const successExample = {
|
2672
|
+
success: true,
|
2673
|
+
name: 'Profile_76561199277912057',
|
2674
|
+
start: 0,
|
2675
|
+
pagesize: '6',
|
2676
|
+
total_count: 0,
|
2677
|
+
upvotes: 0,
|
2678
|
+
has_upvoted: 0,
|
2679
|
+
comments_html: '',
|
2680
|
+
timelastpost: 0
|
2681
|
+
}
|
2682
|
+
}
|
2683
|
+
|
2684
|
+
_formatCommentModel(comment) {
|
2685
|
+
if(comment?.comments_html) {
|
2686
|
+
comment.commentID = comment.comments_html?.substringAfter('javascript:CCommentThread.DeleteComment')
|
2687
|
+
?.substringAfter('\', \'')
|
2688
|
+
?.substringBefore('\' );')
|
2689
|
+
comment.steamID = comment.comments_html?.substringAfter('javascript:CCommentThread.DeleteComment( \'Profile_')
|
2690
|
+
?.substringBefore('\', \'')
|
2691
|
+
}
|
2692
|
+
return comment
|
2693
|
+
}
|
2694
|
+
|
2695
|
+
_formatPlayingTime(hrs) {
|
2696
|
+
if(typeof hrs !== 'string') {
|
2697
|
+
return hrs
|
2698
|
+
}
|
2699
|
+
hrs = hrs.trim()
|
2700
|
+
if(hrs.endsWith('hrs')) {
|
2701
|
+
return parseFloat(hrs.substringBefore('hrs'))
|
2702
|
+
}
|
2703
|
+
return hrs
|
2704
|
+
}
|
2705
|
+
|
2706
|
+
//sorted: false, ASC, DESC
|
2707
|
+
async getFriendsThatPlay(appID, sorted = false) {
|
2708
|
+
if(!appID) {
|
2709
|
+
return
|
2710
|
+
}
|
2711
|
+
const _self = this
|
2712
|
+
const result = await this._httpRequest(`${this.getMySteamUserProfileURL()}/friendsthatplay/${appID}`)
|
2713
|
+
const data = {
|
2714
|
+
YourOwnPlaytime: [],//Your own playtime _
|
2715
|
+
FriendsCurrentlyPlaying: [],//Friends currently playing Counter-Strike: Global Offensive_
|
2716
|
+
FriendsTwoWeeks: [],//Friends who have played Counter-Strike: Global Offensive in the last 2 weeks _
|
2717
|
+
FriendsPreviously: [],//Friends who have played Counter-Strike: Global Offensive previously _
|
2718
|
+
FriendsAddedLibrary: [],//Friends who have Counter-Strike: Global Offensive in their library _
|
2719
|
+
}
|
2720
|
+
if(!result.data) {
|
2721
|
+
return data
|
2722
|
+
}
|
2723
|
+
const $ = result._$()
|
2724
|
+
let currentList
|
2725
|
+
|
2726
|
+
$('#memberList').children(function () {
|
2727
|
+
const el = $(this)
|
2728
|
+
if(el.hasClass('mainSectionHeader')) {
|
2729
|
+
const title = el.text()?.trim() || ''
|
2730
|
+
if(title.startsWith('Your own playtime')) {
|
2731
|
+
currentList = data.YourOwnPlaytime
|
2732
|
+
}
|
2733
|
+
else if(title.startsWith('Friends currently playing')) {
|
2734
|
+
currentList = data.FriendsCurrentlyPlaying
|
2735
|
+
}
|
2736
|
+
else if(title.startsWith('Friends who have played') && title.includes('in the last 2 weeks')) {
|
2737
|
+
currentList = data.FriendsTwoWeeks
|
2738
|
+
}
|
2739
|
+
else if(title.startsWith('Friends who have played') && title.includes('previously')) {
|
2740
|
+
currentList = data.FriendsPreviously
|
2741
|
+
}
|
2742
|
+
else if(title.startsWith('Friends who have') && !title.startsWith('Friends who have played') && title.includes('in their library')) {
|
2743
|
+
currentList = data.FriendsAddedLibrary
|
2744
|
+
}
|
2745
|
+
}
|
2746
|
+
else if(el.hasClass('profile_friends')) {
|
2747
|
+
el.find('.friendBlock.persona').each(function () {
|
2748
|
+
const friendBlock = $(this)
|
2749
|
+
const miniprofile = parseInt(friendBlock.attr('data-miniprofile'))
|
2750
|
+
let onlineStatus = ''
|
2751
|
+
if(friendBlock.hasClass('in-game')) {
|
2752
|
+
onlineStatus = 'ingame'
|
2753
|
+
}
|
2754
|
+
else if(friendBlock.hasClass('online')) {
|
2755
|
+
onlineStatus = 'online'
|
2756
|
+
}
|
2757
|
+
else if(friendBlock.hasClass('offline')) {
|
2758
|
+
onlineStatus = 'offline'
|
2759
|
+
}
|
2760
|
+
const friendBlockContent = friendBlock.find('.friendBlockContent')
|
2761
|
+
friendBlock.find('.friendSmallText .whiteLink').remove()
|
2762
|
+
const friendSmallText = friendBlockContent.find('.friendSmallText').text()?.trim()
|
2763
|
+
|
2764
|
+
const playingTime = {
|
2765
|
+
last2Week: '',
|
2766
|
+
total: '',
|
2767
|
+
}
|
2768
|
+
if(friendSmallText) {
|
2769
|
+
if(friendSmallText.includes('/')) {
|
2770
|
+
playingTime.last2Week = _self._formatPlayingTime(friendSmallText.substringBeforeOrNull('/')?.trim())
|
2771
|
+
playingTime.total = _self._formatPlayingTime(friendSmallText.substringAfterOrNull('/')?.trim())
|
2772
|
+
}
|
2773
|
+
else {
|
2774
|
+
playingTime.total = _self._formatPlayingTime(friendSmallText)
|
2775
|
+
}
|
2776
|
+
}
|
2777
|
+
|
2778
|
+
friendBlockContent.find('.friendSmallText').remove()
|
2779
|
+
const name = friendBlockContent.text()?.trim()
|
2780
|
+
|
2781
|
+
|
2782
|
+
currentList.push({
|
2783
|
+
playingTime,
|
2784
|
+
name,
|
2785
|
+
onlineStatus,
|
2786
|
+
miniprofile,
|
2787
|
+
})
|
2788
|
+
})
|
2789
|
+
}
|
2790
|
+
|
2791
|
+
})
|
2792
|
+
|
2793
|
+
|
2794
|
+
if(sorted) {
|
2795
|
+
const order = sorted === 'ASC' ? 1 : -1
|
2796
|
+
for (let key in data) {
|
2797
|
+
data[key].sort(function (player1, player2) {
|
2798
|
+
const player1_last2Week = player1.playingTime?.last2Week || 0
|
2799
|
+
const player2_last2Week = player2.playingTime?.last2Week || 0
|
2800
|
+
|
2801
|
+
if(player1_last2Week > player2_last2Week) {
|
2802
|
+
return order
|
2803
|
+
}
|
2804
|
+
else if(player1_last2Week < player2_last2Week) {
|
2805
|
+
return -order
|
2806
|
+
}
|
2807
|
+
else {
|
2808
|
+
const player1_total = player1.playingTime?.total || 0
|
2809
|
+
const player2_total = player2.playingTime?.total || 0
|
2810
|
+
if(player1_total > player2_total) {
|
2811
|
+
return order
|
2812
|
+
}
|
2813
|
+
else if(player1_total < player2_total) {
|
2814
|
+
return -order
|
2815
|
+
}
|
2816
|
+
else {
|
2817
|
+
return 0
|
2818
|
+
}
|
2819
|
+
}
|
2820
|
+
})
|
2821
|
+
}
|
2822
|
+
}
|
2823
|
+
|
2824
|
+
return data
|
2825
|
+
}
|
2826
|
+
|
2827
|
+
async getOwnedAppsDetail() {
|
2828
|
+
const response = await this._httpRequest(`${this.getMySteamUserProfileURL()}/games/?tab=all`)
|
2829
|
+
|
2830
|
+
let rgGames = response
|
2831
|
+
?.data
|
2832
|
+
?.substringBetweenOrNull('var rgGames = ', 'var rgChangingGames = []')
|
2833
|
+
?.trim()
|
2834
|
+
?.removeSuffix(';')
|
2835
|
+
?.trim()
|
2836
|
+
if(!rgGames) {
|
2837
|
+
return
|
2838
|
+
}
|
2839
|
+
|
2840
|
+
rgGames = JSON_parse(rgGames)
|
2841
|
+
return rgGames
|
2842
|
+
const resultExample = [{
|
2843
|
+
appid: 730,
|
2844
|
+
name: 'Counter-Strike: Global Offensive',
|
2845
|
+
friendly_name: 'CSGO',
|
2846
|
+
has_adult_content: 1,
|
2847
|
+
is_visible_in_steam_china: 1,
|
2848
|
+
app_type: 1,
|
2849
|
+
logo: 'https://cdn.cloudflare.steamstatic.com/steam/apps/730/capsule_184x69.jpg',
|
2850
|
+
friendlyURL: 'CSGO',
|
2851
|
+
availStatLinks: {
|
2852
|
+
achievements: true,
|
2853
|
+
global_achievements: true,
|
2854
|
+
stats: false,
|
2855
|
+
gcpd: true,
|
2856
|
+
leaderboards: false,
|
2857
|
+
global_leaderboards: false
|
2858
|
+
},
|
2859
|
+
hours: '41.3',
|
2860
|
+
hours_forever: '4,297',
|
2861
|
+
last_played: 1659900692
|
2862
|
+
},]
|
2863
|
+
}
|
2864
|
+
|
2865
|
+
async GetOwnedApps() {
|
2866
|
+
let response = await this._httpRequest(`/actions/GetOwnedApps/?sessionid=${this.getSessionid()}`)
|
2867
|
+
return response?.data
|
2868
|
+
const resultExample = [{
|
2869
|
+
appid: 730,
|
2870
|
+
name: 'Counter-Strike: Global Offensive',
|
2871
|
+
icon: 'https:\/\/cdn.akamai.steamstatic.com\/steamcommunity\/public\/images\/apps\/730\/69f7ebe2735c366c65c0b33dae00e12dc40edbe4.jpg',
|
2872
|
+
logo: 'https:\/\/cdn.akamai.steamstatic.com\/steam\/apps\/730\/capsule_184x69.jpg'
|
2873
|
+
}]
|
2874
|
+
}
|
2875
|
+
|
2876
|
+
async getOwnedAppsID() {
|
2877
|
+
let response = await this._httpRequest(`https://store.steampowered.com/dynamicstore/userdata/?id=${this._miniprofile_user}`)
|
2878
|
+
return response?.data?.rgOwnedApps
|
2879
|
+
const resultExample = [730, 223750,]
|
2880
|
+
}
|
2881
|
+
|
2882
|
+
async getListGroupInvitable(userSteamID) {
|
2883
|
+
const result = await this._httpRequestAjax(`${this.getSteamUserProfileURL(userSteamID)}/ajaxgroupinvite?new_profile=1`)
|
2884
|
+
const $ = result._$()
|
2885
|
+
const groupList = []
|
2886
|
+
$('.group_list_results > .group_list_option').each(function () {
|
2887
|
+
const group_list_option = $(this)
|
2888
|
+
const id = group_list_option.attr('data-groupid')
|
2889
|
+
const avatarHash = group_list_option.attr('_groupavatarhash')
|
2890
|
+
const avatar = group_list_option.find('.playerAvatar img').attr('src')
|
2891
|
+
const name = group_list_option.find('.group_list_groupname').text()?.trim()
|
2892
|
+
groupList.push({
|
2893
|
+
id,
|
2894
|
+
avatarHash,
|
2895
|
+
avatar,
|
2896
|
+
name,
|
2897
|
+
})
|
2898
|
+
})
|
2899
|
+
return groupList
|
2900
|
+
const resultExample = [{
|
2901
|
+
id: NatriGroupSteamID,
|
2902
|
+
avatarHash: '71213b7e643da6216b1f8d8a381fc09b7c1932ef',
|
2903
|
+
avatar: 'https://avatars.cloudflare.steamstatic.com/71213b7e643da6216b1f8d8a381fc09b7c1932ef.jpg',
|
2904
|
+
name: '♔⌒Natri'
|
2905
|
+
}]
|
2906
|
+
}
|
2907
|
+
|
2908
|
+
async inviteUserToGroup(userSteamIDs = [], groupSteamID) {
|
2909
|
+
const params = {
|
2910
|
+
json: 1,
|
2911
|
+
type: 'groupInvite',
|
2912
|
+
group: groupSteamID,
|
2913
|
+
invitee: userSteamIDs,
|
2914
|
+
}
|
2915
|
+
if(userSteamIDs instanceof Array && userSteamIDs.length === 1) {
|
2916
|
+
userSteamIDs = userSteamIDs[0]
|
2917
|
+
}
|
2918
|
+
|
2919
|
+
if(typeof userSteamIDs === 'string') {
|
2920
|
+
params.invitee = userSteamIDs
|
2921
|
+
}
|
2922
|
+
else if(userSteamIDs instanceof Array) {
|
2923
|
+
params.invitee_list = JSON_stringify(userSteamIDs)
|
2924
|
+
}
|
2925
|
+
else {
|
2926
|
+
//error
|
2927
|
+
}
|
2928
|
+
const {data} = await this._httpRequestAjax({
|
2929
|
+
url: 'actions/GroupInvite',
|
2930
|
+
data: params,
|
2931
|
+
method: 'POST',
|
2932
|
+
})
|
2933
|
+
return data
|
2934
|
+
const errorExample = {
|
2935
|
+
results: 'The invite to this user failed for the following reason...',
|
2936
|
+
rgAccounts: {
|
2937
|
+
1317646329: {
|
2938
|
+
persona: '<a href="https://steamcommunity.com/profiles/76561199277912057" data-miniprofile="1317646329">Natri</a>',
|
2939
|
+
strError: 'This user has already been invited or is currently a member.'
|
2940
|
+
}
|
2941
|
+
}
|
2942
|
+
}
|
2943
|
+
const successExample = {
|
2944
|
+
results: 'OK',
|
2945
|
+
groupId: NatriGroupSteamID
|
2946
|
+
}
|
2947
|
+
}
|
2948
|
+
|
2949
|
+
async inviteAllFriendToGroup(groupSteamID) {
|
2950
|
+
const friendList = await this.getMyFriendsList()
|
2951
|
+
for (const {steamId} of friendList) {
|
2952
|
+
const groupInvitableList = await this.getListGroupInvitable(steamId)
|
2953
|
+
if(groupInvitableList.some(g => g.id == groupSteamID)) {
|
2954
|
+
await this.inviteUserToGroup(steamId, groupSteamID)
|
2955
|
+
}
|
2956
|
+
}
|
2957
|
+
}
|
2958
|
+
|
2959
|
+
async _respondToGroupInvite(groupSteamID, accept) {
|
2960
|
+
const {data} = await this._httpRequestAjax({
|
2961
|
+
url: `${this.getMySteamUserProfileURL()}/friends/action`,
|
2962
|
+
data: {
|
2963
|
+
steamid: this.getSteamidUser(),
|
2964
|
+
ajax: 1,
|
2965
|
+
action: accept ? 'group_accept' : 'group_ignore',
|
2966
|
+
'steamids[]': groupSteamID,
|
2967
|
+
},
|
2968
|
+
method: 'POST',
|
2969
|
+
})
|
2970
|
+
|
2971
|
+
return data?.success === 1 || data?.success === true
|
2972
|
+
|
2973
|
+
const errorExample = {
|
2974
|
+
success: 42,//2
|
2975
|
+
rgCounts: {
|
2976
|
+
cFriendsPending: 11,
|
2977
|
+
cFriendsBlocked: 1,
|
2978
|
+
cFollowing: 179,
|
2979
|
+
cGroupsPending: 0,
|
2980
|
+
cFriends: 183,
|
2981
|
+
cGroups: 1,
|
2982
|
+
success: 1
|
2983
|
+
}
|
2984
|
+
}
|
2985
|
+
|
2986
|
+
const successExample = {
|
2987
|
+
success: 1,
|
2988
|
+
rgCounts: {
|
2989
|
+
cFriendsPending: 0,
|
2990
|
+
cFriendsBlocked: 0,
|
2991
|
+
cFollowing: 0,
|
2992
|
+
cGroupsPending: 0,
|
2993
|
+
cFriends: 1,
|
2994
|
+
cGroups: 1,
|
2995
|
+
success: 1
|
2996
|
+
}
|
2997
|
+
}
|
2998
|
+
}
|
2999
|
+
|
3000
|
+
async acceptInviteUserToGroup(groupSteamID) {
|
3001
|
+
return this._respondToGroupInvite(groupSteamID, true)
|
3002
|
+
}
|
3003
|
+
|
3004
|
+
async ignoreInviteUserToGroup(groupSteamID) {
|
3005
|
+
return this._respondToGroupInvite(groupSteamID, false)
|
3006
|
+
}
|
3007
|
+
|
3008
|
+
async leaveGroup(groupSteamID) {
|
3009
|
+
const {data} = await this._httpRequestAjax({
|
3010
|
+
url: `${this.getMySteamUserProfileURL()}/friends/action`,
|
3011
|
+
data: {
|
3012
|
+
steamid: this.getSteamidUser(),
|
3013
|
+
ajax: 1,
|
3014
|
+
action: 'leave_group',
|
3015
|
+
'steamids[]': groupSteamID,
|
3016
|
+
},
|
3017
|
+
method: 'POST',
|
3018
|
+
})
|
3019
|
+
|
3020
|
+
return data?.success === 1 || data?.success === true
|
3021
|
+
|
3022
|
+
const successExample = {
|
3023
|
+
success: true,
|
3024
|
+
rgCounts: {
|
3025
|
+
cFriendsPending: 0,
|
3026
|
+
cFriendsBlocked: 0,
|
3027
|
+
cFollowing: 0,
|
3028
|
+
cGroupsPending: 0,
|
3029
|
+
cFriends: 1,
|
3030
|
+
cGroups: 0,
|
3031
|
+
success: 1
|
3032
|
+
}
|
3033
|
+
}
|
3034
|
+
}
|
3035
|
+
|
3036
|
+
async joinGroup(groupSteamID) {
|
3037
|
+
const result = await this._httpRequest({
|
3038
|
+
url: `/gid/${groupSteamID}/friends/action`,
|
3039
|
+
data: {
|
3040
|
+
action: 'join',
|
3041
|
+
},
|
3042
|
+
method: 'POST',
|
3043
|
+
})
|
3044
|
+
if(!result?.data) {
|
3045
|
+
return {
|
3046
|
+
success: false
|
3047
|
+
}
|
3048
|
+
}
|
3049
|
+
|
3050
|
+
if(result.data.includes('You are already a member of this group.')) {
|
3051
|
+
return {
|
3052
|
+
success: false,
|
3053
|
+
error: 'You are already a member of this group.'
|
3054
|
+
}
|
3055
|
+
}
|
3056
|
+
|
3057
|
+
const $ = result._$()
|
3058
|
+
return {
|
3059
|
+
success: !!($('form#leave_group_form').length)
|
3060
|
+
}
|
3061
|
+
}
|
3062
|
+
|
3063
|
+
async getFriendsInCommon(steamID) {
|
3064
|
+
const accountid = SteamUser.steamID642Miniprofile(steamID)
|
3065
|
+
const result = await this._httpRequest({
|
3066
|
+
url: `actions/PlayerList/?type=friendsincommon&target=${accountid}`,
|
3067
|
+
})
|
3068
|
+
return this._parseFriendList(result?.data)
|
3069
|
+
}
|
3070
|
+
|
3071
|
+
async getFriendsInGroup(groupID) {
|
3072
|
+
const accountid = SteamUser.steamID642Miniprofile(groupID)
|
3073
|
+
const result = await this._httpRequest({
|
3074
|
+
url: `actions/PlayerList/?type=friendsingroup&target=${accountid}`,
|
3075
|
+
})
|
3076
|
+
return this._parseFriendList(result?.data)
|
3077
|
+
}
|
3078
|
+
|
3079
|
+
_parseSteamWebAPIKey($) {
|
3080
|
+
if($('form[action*="/dev/registerkey"]').length) {
|
3081
|
+
return {
|
3082
|
+
success: false,
|
3083
|
+
error: 'registerkey'
|
3084
|
+
}
|
3085
|
+
}
|
3086
|
+
|
3087
|
+
let key = null
|
3088
|
+
$('#bodyContents_ex > p').each(function () {
|
3089
|
+
if(!key) {
|
3090
|
+
const text = $(this).text()?.trim()
|
3091
|
+
if(text.startsWith('Key:')) {
|
3092
|
+
key = text.substringAfter('Key:').trim()
|
3093
|
+
}
|
3094
|
+
}
|
3095
|
+
})
|
3096
|
+
|
3097
|
+
return {
|
3098
|
+
success: true,
|
3099
|
+
key,
|
3100
|
+
}
|
3101
|
+
}
|
3102
|
+
|
3103
|
+
async getSteamWebAPIKey(domain = 'localhost') {
|
3104
|
+
const _self = this
|
3105
|
+
const result = await this._httpRequest({
|
3106
|
+
url: `dev/apikey`,
|
3107
|
+
})
|
3108
|
+
|
3109
|
+
if(result?.data?.includes('You will be granted access to Steam Web API keys when you have games in your Steam account.')) {
|
3110
|
+
return {
|
3111
|
+
success: false,
|
3112
|
+
error: 'dontHaveGames'
|
3113
|
+
}
|
3114
|
+
}
|
3115
|
+
|
3116
|
+
const parseResult = _self._parseSteamWebAPIKey(result._$())
|
3117
|
+
if(parseResult.error === 'registerkey') {
|
3118
|
+
const result2 = await this._httpRequest({
|
3119
|
+
url: `dev/registerkey`,
|
3120
|
+
data: {
|
3121
|
+
domain,
|
3122
|
+
agreeToTerms: 'agreed',
|
3123
|
+
Submit: 'agreRegistered',
|
3124
|
+
},
|
3125
|
+
headers: {
|
3126
|
+
'Content-Type': 'multipart/form-data',
|
3127
|
+
},
|
3128
|
+
method: 'POST',
|
3129
|
+
})
|
3130
|
+
return _self._parseSteamWebAPIKey(result2._$())
|
3131
|
+
}
|
3132
|
+
else {
|
3133
|
+
return parseResult
|
3134
|
+
}
|
3135
|
+
}
|
3136
|
+
|
3137
|
+
async revokeSteamWebAPIKey() {
|
3138
|
+
const _self = this
|
3139
|
+
const result = await this._httpRequest({
|
3140
|
+
url: `dev/revokekey`,
|
3141
|
+
data: {
|
3142
|
+
Revoke: 'Revoke My Steam Web API Key'
|
3143
|
+
},
|
3144
|
+
headers: {
|
3145
|
+
'Content-Type': 'multipart/form-data',
|
3146
|
+
},
|
3147
|
+
method: 'POST',
|
3148
|
+
})
|
3149
|
+
|
3150
|
+
const parseResult = _self._parseSteamWebAPIKey(result._$())
|
3151
|
+
return parseResult
|
3152
|
+
}
|
3153
|
+
|
3154
|
+
_parsePlayerListFromblotter_daily_rollup_line($, contentEl) {
|
3155
|
+
const players = []
|
3156
|
+
contentEl.find('a[data-miniprofile]').each((index, el) => {
|
3157
|
+
el = $(el)
|
3158
|
+
const nickname = el.find('.nickname_name').text()
|
3159
|
+
const miniprofile = parseInt(el.attr('data-miniprofile'))
|
3160
|
+
el.find('.nickname_block').remove()
|
3161
|
+
el.find('.nickname_name').remove()
|
3162
|
+
const name = el.text()?.trim()
|
3163
|
+
players.push({
|
3164
|
+
name,
|
3165
|
+
nickname,
|
3166
|
+
miniprofile,
|
3167
|
+
steamID: SteamUser.miniprofile2SteamID64(miniprofile)
|
3168
|
+
})
|
3169
|
+
})
|
3170
|
+
return players
|
3171
|
+
}
|
3172
|
+
|
3173
|
+
_parseAppIDFromLink(link) {
|
3174
|
+
const prefixs = ['steamcommunity.com/app/', 'store.steampowered.com/app/', 'store.steampowered.com/sub/']
|
3175
|
+
for (let i = 0; i < prefixs.length; i++) {
|
3176
|
+
const prefix = prefixs[i]
|
3177
|
+
if(link.includes(prefix)) {
|
3178
|
+
link = link.substringAfter(prefix)
|
3179
|
+
if(link.includes('/')) {
|
3180
|
+
link = link.substringBefore('/')
|
3181
|
+
}
|
3182
|
+
return parseInt(link)
|
3183
|
+
}
|
3184
|
+
}
|
3185
|
+
|
3186
|
+
return -1
|
3187
|
+
}
|
3188
|
+
|
3189
|
+
_parseAppListFromBlotter($, contentEl) {
|
3190
|
+
const _self = this
|
3191
|
+
|
3192
|
+
let apps = []
|
3193
|
+
contentEl.find('a').each((index, appEl) => {
|
3194
|
+
appEl = $(appEl)
|
3195
|
+
const link = appEl.attr('href')
|
3196
|
+
const id = _self._parseAppIDFromLink(link)
|
3197
|
+
const name = appEl.text()?.trim()
|
3198
|
+
apps.push({
|
3199
|
+
name,
|
3200
|
+
link,
|
3201
|
+
id,
|
3202
|
+
})
|
3203
|
+
})
|
3204
|
+
apps = apps.filter(app => app.link && app.id !== -1)
|
3205
|
+
return apps
|
3206
|
+
}
|
3207
|
+
|
3208
|
+
_parseAchievedblotter_daily_rollup_line($, contentEl) {
|
3209
|
+
const achieved = []
|
3210
|
+
contentEl.find('> img[title]').each((index, imgEl) => {
|
3211
|
+
imgEl = $(imgEl)
|
3212
|
+
const img = imgEl.attr('src')
|
3213
|
+
const title = imgEl.attr('title')
|
3214
|
+
achieved.push({
|
3215
|
+
img,
|
3216
|
+
title
|
3217
|
+
})
|
3218
|
+
})
|
3219
|
+
return achieved
|
3220
|
+
}
|
3221
|
+
|
3222
|
+
_parseGroupListFromblotter_daily_rollup_line($, contentEl) {
|
3223
|
+
const groups = []
|
3224
|
+
contentEl.find('a[href*="steamcommunity.com/groups/"]').each((index, appEl) => {
|
3225
|
+
appEl = $(appEl)
|
3226
|
+
const link = appEl.attr('href')
|
3227
|
+
if(link) {
|
3228
|
+
groups.push({
|
3229
|
+
name: appEl.text()?.trim(),
|
3230
|
+
link: link,
|
3231
|
+
URL: link.substringAfter('steamcommunity.com/groups/').removeSuffix('/'),
|
3232
|
+
})
|
3233
|
+
}
|
3234
|
+
})
|
3235
|
+
return groups
|
3236
|
+
}
|
3237
|
+
|
3238
|
+
_parseBlotterDailyRollup($, blotterBlockEl) {
|
3239
|
+
const _self = this
|
3240
|
+
const activity = []
|
3241
|
+
blotterBlockEl.find('.blotter_daily_rollup_line').each(function () {
|
3242
|
+
const blotter_daily_rollup_line = $(this)
|
3243
|
+
const miniprofile = parseInt(blotter_daily_rollup_line.find('.blotter_rollup_avatar .blotter_small_friend_block_container img[data-miniprofile]').attr('data-miniprofile'))
|
3244
|
+
const steamID = SteamUser.miniprofile2SteamID64(miniprofile)
|
3245
|
+
const contentEl = $(blotter_daily_rollup_line.find(' > span')[0])
|
3246
|
+
const contentText = contentEl.text()?.trim()
|
3247
|
+
|
3248
|
+
const players = () => _self._parsePlayerListFromblotter_daily_rollup_line($, contentEl)
|
3249
|
+
const apps = () => _self._parseAppListFromBlotter($, contentEl)
|
3250
|
+
const groups = () => _self._parseGroupListFromblotter_daily_rollup_line($, contentEl)
|
3251
|
+
const achieved = () => _self._parseAchievedblotter_daily_rollup_line($, blotter_daily_rollup_line)
|
3252
|
+
|
3253
|
+
if(contentText.includes('and') && contentText.includes(' are now friends.')) {
|
3254
|
+
activity.push({
|
3255
|
+
type: EActivityType.newFriend,
|
3256
|
+
players: players(),
|
3257
|
+
})
|
3258
|
+
}
|
3259
|
+
else if(contentText.includes(' is now friends with ')) {
|
3260
|
+
activity.push({
|
3261
|
+
type: EActivityType.newFriend,
|
3262
|
+
players: players(),
|
3263
|
+
})
|
3264
|
+
}
|
3265
|
+
else if(contentText.includes(' played ') && contentText.includes('for the first time.')) {
|
3266
|
+
activity.push({
|
3267
|
+
type: EActivityType.playedFirstTime,
|
3268
|
+
players: players(),
|
3269
|
+
apps: apps(),
|
3270
|
+
})
|
3271
|
+
}
|
3272
|
+
else if(contentText.includes(' achieved ')) {
|
3273
|
+
activity.push({
|
3274
|
+
type: EActivityType.achieved,
|
3275
|
+
players: players(),
|
3276
|
+
apps: apps(),
|
3277
|
+
achieved: achieved(),
|
3278
|
+
})
|
3279
|
+
}
|
3280
|
+
else if(contentText.includes(' has added ') && contentText.includes('to their wishlist.')) {
|
3281
|
+
activity.push({
|
3282
|
+
type: EActivityType.added2wishlist,
|
3283
|
+
players: players(),
|
3284
|
+
apps: apps(),
|
3285
|
+
})
|
3286
|
+
}
|
3287
|
+
else if(contentText.includes(' is now following ')) {
|
3288
|
+
activity.push({
|
3289
|
+
type: EActivityType.following,
|
3290
|
+
players: players(),
|
3291
|
+
apps: apps(),
|
3292
|
+
})
|
3293
|
+
}
|
3294
|
+
else if(contentText.includes(' has joined ')) {
|
3295
|
+
activity.push({
|
3296
|
+
type: EActivityType.joined,
|
3297
|
+
players: players(),
|
3298
|
+
groups: groups(),
|
3299
|
+
})
|
3300
|
+
}
|
3301
|
+
else {
|
3302
|
+
console_log(contentText)
|
3303
|
+
}
|
3304
|
+
})
|
3305
|
+
return activity
|
3306
|
+
}
|
3307
|
+
|
3308
|
+
_parseBlotterGamepurchase($, blotterBlockEl) {
|
3309
|
+
const _self = this
|
3310
|
+
const activity = []
|
3311
|
+
const authorAvatarEl = blotterBlockEl.find('.blotter_author_block .blotter_avatar_holder .playerAvatar img')
|
3312
|
+
const miniprofile = parseInt(authorAvatarEl.attr('data-miniprofile'))
|
3313
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL(authorAvatarEl.attr('src'))
|
3314
|
+
const authorEl = $(blotterBlockEl.find(`a[data-miniprofile="${miniprofile}"]`)[0]).clone()
|
3315
|
+
const nickname = authorEl.find('.nickname_name').text()
|
3316
|
+
authorEl.find('.nickname_block').remove()
|
3317
|
+
authorEl.find('.nickname_name').remove()
|
3318
|
+
const profileURL = authorEl.attr('href')
|
3319
|
+
const customURL = SteamUser.getCustomURL_from_ProfileURL(profileURL)
|
3320
|
+
const name = authorEl.text()?.trim()
|
3321
|
+
|
3322
|
+
const apps = []
|
3323
|
+
const appppp = [..._self._parseAppListFromBlotter($, blotterBlockEl.find('.blotter_author_block')), ..._self._parseAppListFromBlotter($, blotterBlockEl.find('.blotter_gamepurchase_content')), ..._self._parseAppListFromBlotter($, blotterBlockEl.find('.blotter_gamepurchase_details'))]
|
3324
|
+
|
3325
|
+
appppp.forEach(app => {
|
3326
|
+
const index = apps.findIndex(_app => _app.id === app.id)
|
3327
|
+
if(index === -1) {
|
3328
|
+
apps.push(app)
|
3329
|
+
}
|
3330
|
+
else {
|
3331
|
+
for (let key in apps[index]) {
|
3332
|
+
if(!apps[index][key] && app[key]) {
|
3333
|
+
apps[index][key] = app[key]
|
3334
|
+
}
|
3335
|
+
}
|
3336
|
+
}
|
3337
|
+
})
|
3338
|
+
|
3339
|
+
const author = {
|
3340
|
+
name,
|
3341
|
+
nickname,
|
3342
|
+
avatarHash,
|
3343
|
+
miniprofile,
|
3344
|
+
steamID: SteamUser.miniprofile2SteamID64(miniprofile),
|
3345
|
+
url: profileURL,
|
3346
|
+
customURL,
|
3347
|
+
}
|
3348
|
+
|
3349
|
+
activity.push({
|
3350
|
+
type: EActivityType.own,
|
3351
|
+
author,
|
3352
|
+
apps,
|
3353
|
+
})
|
3354
|
+
return activity
|
3355
|
+
}
|
3356
|
+
|
3357
|
+
async getFriendActivity(start_or_url) {//start or next_request
|
3358
|
+
start_or_url = start_or_url || Math.round((new Date()).getTime() / 1000)
|
3359
|
+
const _self = this
|
3360
|
+
const activity = []
|
3361
|
+
let next_request_timestart = null,
|
3362
|
+
next_request = null
|
3363
|
+
const {data} = await this._httpRequestAjax(typeof start_or_url === 'string' ? start_or_url : `my/ajaxgetusernews/?start=${start_or_url}`)//use my, not profiles/76561197977736539 getMySteamUserProfileURL
|
3364
|
+
if(data?.success) {
|
3365
|
+
next_request = data.next_request || null
|
3366
|
+
next_request_timestart = parseInt(next_request.substringAfterLast('?start=')) || null
|
3367
|
+
const $ = cheerio.load(data.blotter_html
|
3368
|
+
.replaceAll(/[\t\n\r]/gi, '')
|
3369
|
+
.trim())
|
3370
|
+
$('.blotter_day').each(function () {
|
3371
|
+
const blotter_day = $(this)
|
3372
|
+
const timestamp = parseInt(blotter_day.attr('id').substringAfter('blotter_day_'))
|
3373
|
+
const header_date = blotter_day.find('.blotter_day_header_date').text()
|
3374
|
+
|
3375
|
+
let _activity = []
|
3376
|
+
|
3377
|
+
const activityType = {
|
3378
|
+
daily_rollup(blotterBlockEl) {
|
3379
|
+
return _self._parseBlotterDailyRollup($, blotterBlockEl)
|
3380
|
+
},
|
3381
|
+
gamepurchase(blotterBlockEl) {
|
3382
|
+
return _self._parseBlotterGamepurchase($, blotterBlockEl)
|
3383
|
+
},
|
3384
|
+
workshopitempublished() {
|
3385
|
+
|
3386
|
+
},
|
3387
|
+
recommendation() {
|
3388
|
+
|
3389
|
+
},
|
3390
|
+
userstatus() {
|
3391
|
+
|
3392
|
+
},
|
3393
|
+
screenshot() {//screenshot_fullscreen
|
3394
|
+
|
3395
|
+
},
|
3396
|
+
videopublished() {
|
3397
|
+
|
3398
|
+
},
|
3399
|
+
}
|
3400
|
+
|
3401
|
+
|
3402
|
+
blotter_day.find('.blotter_block').each(function (index, blotterBlockEl) {
|
3403
|
+
blotterBlockEl = $(blotterBlockEl)
|
3404
|
+
let type = []
|
3405
|
+
blotterBlockEl.children().each(function () {
|
3406
|
+
const classList = $(this).attr('class')
|
3407
|
+
?.replaceAll('blotter_entry', '')
|
3408
|
+
?.trim()
|
3409
|
+
if(classList) {
|
3410
|
+
type = type.concat(classList.split(' ').map(_class => _class?.removePrefix('blotter_')))
|
3411
|
+
}
|
3412
|
+
})
|
3413
|
+
|
3414
|
+
let excute
|
3415
|
+
if((excute = type.find(_class => Object.hasOwn(activityType, _class)))) {
|
3416
|
+
const __activity = activityType[excute](blotterBlockEl)
|
3417
|
+
if(__activity instanceof Array) {
|
3418
|
+
__activity.forEach(___activity => {
|
3419
|
+
if(!___activity.type) {
|
3420
|
+
___activity.type = excute
|
3421
|
+
}
|
3422
|
+
|
3423
|
+
const activityID = [___activity.type, ___activity.author?.steamID, (___activity.apps?.map?.(app => app.id) || []).sort().join('|'), (___activity.players?.map?.(p => p.steamID) || []).sort().join('|'), (___activity.achieved?.map?.(p => p.title.replaceAll(/\s/gi, '').toLowerCase()) || []).sort().join('|'), (___activity.groups?.map?.(p => p.URL) || []).sort().join('|'),].filter(Boolean)
|
3424
|
+
_activity.push(___activity)
|
3425
|
+
})
|
3426
|
+
}
|
3427
|
+
}
|
3428
|
+
else {
|
3429
|
+
const html = blotterBlockEl.html()
|
3430
|
+
console.log(html)
|
3431
|
+
}
|
3432
|
+
})
|
3433
|
+
_activity.forEach(ac => {
|
3434
|
+
ac.timestamp = timestamp
|
3435
|
+
ac.header_date = header_date
|
3436
|
+
// if (ac.players?.[0]?.name == '𝙎𝙋𝙏 popiii') {
|
3437
|
+
// console_log(ac);
|
3438
|
+
// }
|
3439
|
+
activity.push(ac)
|
3440
|
+
})
|
3441
|
+
})
|
3442
|
+
}
|
3443
|
+
|
3444
|
+
return {
|
3445
|
+
activity,
|
3446
|
+
next_request_timestart,
|
3447
|
+
next_request,
|
3448
|
+
}
|
3449
|
+
}
|
3450
|
+
|
3451
|
+
async getFriendActivityFull({
|
3452
|
+
cbOnActivity,
|
3453
|
+
cbOnActivities
|
3454
|
+
}) {
|
3455
|
+
const iscbOnActivity = typeof cbOnActivity === 'function'
|
3456
|
+
const iscbOnActivities = typeof cbOnActivities === 'function'
|
3457
|
+
let next_request = null
|
3458
|
+
do {
|
3459
|
+
const activities = await this.getFriendActivity(next_request)
|
3460
|
+
next_request = activities.next_request
|
3461
|
+
if(activities.activity instanceof Array) {
|
3462
|
+
iscbOnActivities && cbOnActivities?.(activities.activity)
|
3463
|
+
iscbOnActivity && activities.activity.forEach(function (a) {
|
3464
|
+
cbOnActivity?.(a)
|
3465
|
+
})
|
3466
|
+
}
|
3467
|
+
} while (next_request)
|
3468
|
+
}
|
3469
|
+
|
3470
|
+
async searchSteamUserByName(text, page = 1) {
|
3471
|
+
const {data} = await this._httpRequestAjax(`search/SearchCommunityAjax?text=${encodeURIComponent(text)}&filter=users&sessionid=${this._sessionid}&steamid_user=${this.getSteamidUser()}&page=${page}`)
|
3472
|
+
if(data?.success === 1) {
|
3473
|
+
let {
|
3474
|
+
html,
|
3475
|
+
search_filter,
|
3476
|
+
search_page,
|
3477
|
+
search_result_count,
|
3478
|
+
search_text,
|
3479
|
+
success
|
3480
|
+
} = data
|
3481
|
+
search_page = parseInt(search_page)
|
3482
|
+
const $ = cheerio.load(html.replaceAll(/[\t\n\r]/gi, '').trim())
|
3483
|
+
const players = []
|
3484
|
+
$('.search_row').each(function (index, el) {
|
3485
|
+
el = $(el)
|
3486
|
+
const miniprofile = parseInt(el.find('.mediumHolder_default[data-miniprofile]').attr('data-miniprofile'))
|
3487
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL(el.find('.avatarMedium a img').attr('src'))
|
3488
|
+
const searchPersonaEl = el.find('a.searchPersonaName')
|
3489
|
+
const name = searchPersonaEl.text()?.trim()
|
3490
|
+
const profileURL = searchPersonaEl.attr('href')
|
3491
|
+
players.push({
|
3492
|
+
miniprofile,
|
3493
|
+
steamID: SteamUser.miniprofile2SteamID64(miniprofile),
|
3494
|
+
avatarHash,
|
3495
|
+
name,
|
3496
|
+
profileURL,
|
3497
|
+
customURL: SteamUser.getCustomURL_from_ProfileURL(profileURL),
|
3498
|
+
})
|
3499
|
+
})
|
3500
|
+
|
3501
|
+
let nextPage = null,
|
3502
|
+
prevPage = null
|
3503
|
+
$('.community_searchresults_paging a').each(function (index, pagingEl) {
|
3504
|
+
pagingEl = $(pagingEl)
|
3505
|
+
const onclick = pagingEl.attr('onclick')
|
3506
|
+
if(onclick.includes('CommunitySearch.PrevPage()')) {
|
3507
|
+
prevPage = page - 1
|
3508
|
+
}
|
3509
|
+
else if(onclick.includes('CommunitySearch.NextPage()')) {
|
3510
|
+
nextPage = page + 1
|
3511
|
+
}
|
3512
|
+
})
|
3513
|
+
|
3514
|
+
return {
|
3515
|
+
players,
|
3516
|
+
prevPage,
|
3517
|
+
nextPage,
|
3518
|
+
search_filter,
|
3519
|
+
search_page,
|
3520
|
+
search_result_count,
|
3521
|
+
search_text,
|
3522
|
+
success,
|
3523
|
+
}
|
3524
|
+
}
|
3525
|
+
|
3526
|
+
return {
|
3527
|
+
success: 0
|
3528
|
+
}
|
3529
|
+
}
|
3530
|
+
|
3531
|
+
async getMyGroupsList() {
|
3532
|
+
const steamID = this.getSteamidUser()
|
3533
|
+
return await this.getUserGroupsList(steamID)
|
3534
|
+
}
|
3535
|
+
|
3536
|
+
async getUserGroupsList(steamID = this.getSteamidUser()) {
|
3537
|
+
return await SteamUser.getUserGroupsList(steamID, this.getCookies())
|
3538
|
+
}
|
3539
|
+
|
3540
|
+
static async getUserGroupsList(steamID, cookie) {
|
3541
|
+
const {data} = (await request({
|
3542
|
+
baseURL: SteamcommunityURL,
|
3543
|
+
url: `https://steamcommunity.com/profiles/${steamID}/groups/`,
|
3544
|
+
headers: {...cookie && {cookie}},
|
3545
|
+
}))
|
3546
|
+
return SteamUser._parseUserGroupList(data?.replaceAll(/[\t\n\r]/gi, ''))
|
3547
|
+
}
|
3548
|
+
|
3549
|
+
static _parseUserGroupList(html) {
|
3550
|
+
if(!html) {
|
3551
|
+
return
|
3552
|
+
}
|
3553
|
+
const $ = cheerio.load(html)
|
3554
|
+
const groups = []
|
3555
|
+
$('#groups_list #search_results .group_block').each(function (index, groupEl) {
|
3556
|
+
groupEl = $(groupEl)
|
3557
|
+
const groupTitleEl = groupEl.find('.group_block_details a.linkTitle')
|
3558
|
+
const link = groupTitleEl.attr('href').removeSuffix('/')
|
3559
|
+
const url = link.substringAfter('steamcommunity.com/groups/').removeSuffix('/')
|
3560
|
+
const name = groupTitleEl.text()?.trim()
|
3561
|
+
const gid = groupEl.find('.groupMemberStat[href*="OpenGroupChat"]').attr('href')?.substringBetweenOrNull(`'`, `'`)
|
3562
|
+
const avatarHash = SteamUser.GetAvatarHashFromURL(groupEl.find('div[class*="avatar"] a img[src*="avatars"]').attr('src'))
|
3563
|
+
const groupMemberStat = [...groupEl.find('a, .groupMemberStat')].map(e => $(e).text()?.trim()).filter(Boolean)
|
3564
|
+
const memberCount = SteamUser._formatString2Int(groupMemberStat.find(text => text.endsWith('Members'))?.removeSuffix('Members'))
|
3565
|
+
const membersInGame = SteamUser._formatString2Int(groupMemberStat.find(text => text.endsWith('In-Game'))?.removeSuffix('In-Game'))
|
3566
|
+
const membersOnline = SteamUser._formatString2Int(groupMemberStat.find(text => text.endsWith('Online'))?.removeSuffix('Online'))
|
3567
|
+
const membersInChat = SteamUser._formatString2Int(groupMemberStat.find(text => text.endsWith('In Group Chat'))?.removeSuffix('In Group Chat'))
|
3568
|
+
|
3569
|
+
groups.push({
|
3570
|
+
id: gid,
|
3571
|
+
link,
|
3572
|
+
name,
|
3573
|
+
url,
|
3574
|
+
avatarHash,
|
3575
|
+
memberCount,
|
3576
|
+
membersInGame,
|
3577
|
+
membersOnline,
|
3578
|
+
membersInChat,
|
3579
|
+
})
|
3580
|
+
})
|
3581
|
+
return groups
|
3582
|
+
}
|
3583
|
+
|
3584
|
+
async getNotifications() {
|
3585
|
+
const {data} = await this._httpRequest(`/actions/GetNotificationCounts`)
|
3586
|
+
if(!data) {
|
3587
|
+
return
|
3588
|
+
}
|
3589
|
+
|
3590
|
+
const exampleJSON = {
|
3591
|
+
notifications: {
|
3592
|
+
1: 0,
|
3593
|
+
2: 0,
|
3594
|
+
3: 0,
|
3595
|
+
4: 0,
|
3596
|
+
5: 0,
|
3597
|
+
6: 0,
|
3598
|
+
8: 0,
|
3599
|
+
9: 0,
|
3600
|
+
10: 0,
|
3601
|
+
11: 0
|
3602
|
+
}
|
3603
|
+
}
|
3604
|
+
const mapping1 = {
|
3605
|
+
1: 'Trade offers',
|
3606
|
+
2: 'Games notification (turns waiting)',
|
3607
|
+
3: 'Community messages',
|
3608
|
+
4: 'New comments',
|
3609
|
+
5: 'Inventory',
|
3610
|
+
6: 'Invites',
|
3611
|
+
8: 'Gifts',
|
3612
|
+
9: 'Chat messages',
|
3613
|
+
10: 'Replies from Steam Support',
|
3614
|
+
11: 'Account warning or alert'
|
3615
|
+
}
|
3616
|
+
const mapping = {
|
3617
|
+
1: 'trades',
|
3618
|
+
2: 'gameTurns',
|
3619
|
+
3: 'moderatorMessages',
|
3620
|
+
4: 'comments',
|
3621
|
+
5: 'items',
|
3622
|
+
6: 'invites',
|
3623
|
+
8: 'gifts',
|
3624
|
+
9: 'chat',
|
3625
|
+
10: 'helpRequestReplies',
|
3626
|
+
11: 'accountAlerts'
|
3627
|
+
}
|
3628
|
+
|
3629
|
+
if(data?.notifications) {
|
3630
|
+
Object.keys(data.notifications).forEach(key => {
|
3631
|
+
const value = data.notifications[key]
|
3632
|
+
delete data.notifications[key]
|
3633
|
+
data.notifications[mapping[key]] = value
|
3634
|
+
})
|
3635
|
+
}
|
3636
|
+
return data
|
3637
|
+
|
3638
|
+
const example = {
|
3639
|
+
notifications: {
|
3640
|
+
trades: 0,
|
3641
|
+
gameTurns: 0,
|
3642
|
+
moderatorMessages: 0,
|
3643
|
+
comments: 0,
|
3644
|
+
items: 0,
|
3645
|
+
invites: 8,
|
3646
|
+
gifts: 0,
|
3647
|
+
chat: 0,
|
3648
|
+
helpRequestReplies: 0,
|
3649
|
+
accountAlerts: 0
|
3650
|
+
}
|
3651
|
+
}
|
3652
|
+
}
|
3653
|
+
|
3654
|
+
async addFreeLicense(appID) {
|
3655
|
+
const {data} = await this._httpRequestAjax({
|
3656
|
+
url: `https://store.steampowered.com/checkout/addfreelicense/${appID}`,
|
3657
|
+
data: {
|
3658
|
+
ajax: true
|
3659
|
+
},
|
3660
|
+
method: 'POST',
|
3661
|
+
})
|
3662
|
+
return Array.isArray(data) && !data.length
|
3663
|
+
}
|
3664
|
+
|
3665
|
+
async addSubFreeLicense(subid) {
|
3666
|
+
const {data} = await this._httpRequestAjax({
|
3667
|
+
url: `https://store.steampowered.com/checkout/addfreelicense/`,
|
3668
|
+
data: {
|
3669
|
+
snr: '1_5_9__403',
|
3670
|
+
originating_snr: '1_store-navigation__',
|
3671
|
+
action: 'add_to_cart',
|
3672
|
+
subid: subid,
|
3673
|
+
},
|
3674
|
+
method: 'POST',
|
3675
|
+
})
|
3676
|
+
|
3677
|
+
if(data?.includes('There was a problem adding this product to your Steam account.')) {
|
3678
|
+
return false
|
3679
|
+
}
|
3680
|
+
|
3681
|
+
return data
|
3682
|
+
}
|
3683
|
+
|
3684
|
+
requestFreeLicense = this.addFreeLicense
|
3685
|
+
|
3686
|
+
async getCurrentSteamLogin() {
|
3687
|
+
const result = await this._httpRequest({
|
3688
|
+
url: `${this.getMySteamUserProfileURL()}/games/?tab=all`,
|
3689
|
+
})
|
3690
|
+
const $ = result._$()
|
3691
|
+
return $('.clientConnMachineText').text()?.trim()?.substringBeforeLast('|')?.trim()
|
3692
|
+
}
|
3693
|
+
|
3694
|
+
//not working
|
3695
|
+
async setLanguagePreferences() {
|
3696
|
+
const primary_language_list = ['greek', 'dutch', 'norwegian', 'danish', 'german', 'russian', 'romanian', 'vietnamese', 'bulgarian', 'swedish', 'spanish', 'latam', 'english', 'ukrainian', 'italian', 'japanese', 'schinese', 'tchinese', 'czech', 'thai', 'turkish', 'brazilian', 'portuguese', 'polish', 'french', 'finnish', 'koreana', 'hungarian']
|
3697
|
+
const formData = new URLSearchParams()
|
3698
|
+
formData.append('primary_language', 'koreana')
|
3699
|
+
const {data} = await this._httpRequestAjax({
|
3700
|
+
url: 'https://store.steampowered.com/account/savelanguagepreferences', // data: 'primary_language=english',
|
3701
|
+
data: formData,
|
3702
|
+
headers: {
|
3703
|
+
referer: 'https://store.steampowered.com/account/languagepreferences'
|
3704
|
+
},
|
3705
|
+
method: 'POST'
|
3706
|
+
})
|
3707
|
+
return data
|
3708
|
+
}
|
3709
|
+
|
3710
|
+
async ChangeLanguage() {
|
3711
|
+
const primary_language_list = ['greek', 'dutch', 'norwegian', 'danish', 'german', 'russian', 'romanian', 'vietnamese', 'bulgarian', 'swedish', 'spanish', 'latam', 'english', 'ukrainian', 'italian', 'japanese', 'schinese', 'tchinese', 'czech', 'thai', 'turkish', 'brazilian', 'portuguese', 'polish', 'french', 'finnish', 'koreana', 'hungarian']
|
3712
|
+
const formData = new URLSearchParams()
|
3713
|
+
formData.append('language', 'koreana')
|
3714
|
+
const {data} = await this._httpRequestAjax({
|
3715
|
+
url: 'https://steamcommunity.com/actions/SetLanguage/', // data: 'primary_language=english',
|
3716
|
+
data: formData,
|
3717
|
+
method: 'POST'
|
3718
|
+
})
|
3719
|
+
return data
|
3720
|
+
}
|
3721
|
+
|
3722
|
+
//Personal Game Data
|
3723
|
+
async getCompetitiveCooldownLevel() {
|
3724
|
+
const result = await this._httpRequest({
|
3725
|
+
url: `${this.getMySteamUserProfileURL()}/gcpd/730/?tab=matchmaking`,
|
3726
|
+
})
|
3727
|
+
const $ = result._$()
|
3728
|
+
|
3729
|
+
const $table = $('table.generic_kv_table')
|
3730
|
+
let cooldown_table = table2json($, getTableHasHeaders($, $table, ['Competitive Cooldown Expiration']))
|
3731
|
+
let matchmaking_detail_table = table2json($, getTableHasHeaders($, $table, ['Matchmaking Mode', 'Wins', 'Skill Group']))
|
3732
|
+
let matchmaking_table = getTableHasHeaders($, $table, ['Matchmaking Mode', 'Last Match']).map(t => table2json($, t)).filter(t => Object.keys(t[0]).length === 2)[0]
|
3733
|
+
|
3734
|
+
cooldown_table = cooldown_table.map(function (object) {
|
3735
|
+
removeSpaceKeys(object)
|
3736
|
+
return {
|
3737
|
+
Acknowledged: object.Acknowledged,
|
3738
|
+
Competitive_Cooldown_Expiration: object.Competitive_Cooldown_Expiration,
|
3739
|
+
Competitive_Cooldown_Level: isNaN(parseInt(object.Competitive_Cooldown_Level)) ? object.Competitive_Cooldown_Level : parseInt(object.Competitive_Cooldown_Level),
|
3740
|
+
}
|
3741
|
+
})
|
3742
|
+
|
3743
|
+
matchmaking_detail_table = matchmaking_detail_table.map(function (object) {
|
3744
|
+
removeSpaceKeys(object)
|
3745
|
+
return {
|
3746
|
+
Wins: isNaN(parseInt(object.Wins)) ? object.Wins : parseInt(object.Wins),
|
3747
|
+
Ties: isNaN(parseInt(object.Ties)) ? object.Ties : parseInt(object.Ties),
|
3748
|
+
Losses: isNaN(parseInt(object.Losses)) ? object.Losses : parseInt(object.Losses),
|
3749
|
+
Matchmaking_Mode: object.Matchmaking_Mode,
|
3750
|
+
Skill_Group: isNaN(parseInt(object.Skill_Group)) ? object.Skill_Group : parseInt(object.Skill_Group),
|
3751
|
+
Last_Match: object.Last_Match,
|
3752
|
+
}
|
3753
|
+
})
|
3754
|
+
matchmaking_table = matchmaking_table.map(function (object) {
|
3755
|
+
removeSpaceKeys(object)
|
3756
|
+
return {
|
3757
|
+
Matchmaking_Mode: object.Matchmaking_Mode,
|
3758
|
+
Last_Match: object.Last_Match,//2022-05-02 15:39:48 GMT
|
3759
|
+
}
|
3760
|
+
})
|
3761
|
+
|
3762
|
+
return {
|
3763
|
+
cooldown_table,
|
3764
|
+
matchmaking_detail_table,
|
3765
|
+
matchmaking_table,
|
3766
|
+
}
|
3767
|
+
|
3768
|
+
const resultExample = {
|
3769
|
+
cooldown_table: [{
|
3770
|
+
Acknowledged: 'No',
|
3771
|
+
Competitive_Cooldown_Expiration: '2022-09-10 01:40:36 GMT',
|
3772
|
+
Competitive_Cooldown_Level: 1
|
3773
|
+
}],
|
3774
|
+
matchmaking_detail_table: [{
|
3775
|
+
Wins: 151,
|
3776
|
+
Ties: 20,
|
3777
|
+
Losses: 218,
|
3778
|
+
Matchmaking_Mode: 'Competitive',
|
3779
|
+
Skill_Group: 4,
|
3780
|
+
Last_Match: '2022-08-07 19:30:42 GMT'
|
3781
|
+
}, {
|
3782
|
+
Wins: 1,
|
3783
|
+
Ties: 0,
|
3784
|
+
Losses: 1,
|
3785
|
+
Matchmaking_Mode: 'Wingman',
|
3786
|
+
Skill_Group: '',
|
3787
|
+
Last_Match: '2020-05-29 14:03:30 GMT'
|
3788
|
+
}],
|
3789
|
+
matchmaking_table: [{
|
3790
|
+
Matchmaking_Mode: 'Competitive',
|
3791
|
+
Last_Match: '2022-09-10 01:13:09 GMT'
|
3792
|
+
}, {
|
3793
|
+
Matchmaking_Mode: 'Deathmatch',
|
3794
|
+
Last_Match: '2022-08-16 16:31:35 GMT'
|
3795
|
+
}]
|
3796
|
+
}
|
3797
|
+
}
|
3798
|
+
|
3799
|
+
async getPersonalGameDataAccountInformation() {
|
3800
|
+
const result = await this._httpRequest({
|
3801
|
+
url: `${this.getMySteamUserProfileURL()}/gcpd/730/?tab=accountmain`,
|
3802
|
+
})
|
3803
|
+
if(!result?.data) {
|
3804
|
+
return
|
3805
|
+
}
|
3806
|
+
const $ = result._$()
|
3807
|
+
|
3808
|
+
const $table = $('table.generic_kv_table')
|
3809
|
+
const accountmain_table = table2json($, getTableHasHeaders($, $table, ['Recorded Activity', 'Activity Time']))
|
3810
|
+
.reduce(function (previousValue, currentValue, currentIndex, array) {
|
3811
|
+
return {
|
3812
|
+
...previousValue,
|
3813
|
+
[currentValue['Recorded Activity']]: currentValue['Activity Time']
|
3814
|
+
}
|
3815
|
+
}, {})
|
3816
|
+
|
3817
|
+
const extraInfo = [...($('.generic_kv_table .generic_kv_line'))]
|
3818
|
+
.map(lineEl => $(lineEl).text()?.trim()?.replaceAll('CS:GO', 'CSGO'))
|
3819
|
+
.reduce(function (previousValue, currentValue, currentIndex, array) {
|
3820
|
+
const key = currentValue.substringBefore(':')?.trim()
|
3821
|
+
const value = currentValue.substringAfter(':')?.trim()
|
3822
|
+
previousValue[key] = value
|
3823
|
+
return previousValue
|
3824
|
+
}, {})
|
3825
|
+
|
3826
|
+
const doc = {
|
3827
|
+
...accountmain_table, ...extraInfo,
|
3828
|
+
}
|
3829
|
+
|
3830
|
+
const cleanDoc = getCleanObject(doc)
|
3831
|
+
|
3832
|
+
return {
|
3833
|
+
Logged_out_of_CS_GO: cleanDoc.Logged_out_of_CS_GO,//'2022-09-09 16:14:54 GMT'
|
3834
|
+
Launched_CS_GO_using_Steam_Client: cleanDoc.Launched_CS_GO_using_Steam_Client,//'2022-05-06 10:08:29 GMT'
|
3835
|
+
Started_playing_CS_GO: cleanDoc.Started_playing_CS_GO,//'2022-05-06 10:08:29 GMT'
|
3836
|
+
First_Counter_Strike_franchise_game: cleanDoc.First_Counter_Strike_franchise_game,//'2022-05-06 10:07:35 GMT'
|
3837
|
+
Last_known_IP_address: cleanDoc.Last_known_IP_address,//'42.1.70.156'
|
3838
|
+
Earned_a_Service_Medal: cleanDoc.Earned_a_Service_Medal,//'No' Yes
|
3839
|
+
CSGO_Profile_Rank: isNaN(parseInt(cleanDoc.CSGO_Profile_Rank)) ? cleanDoc.CSGO_Profile_Rank : parseInt(cleanDoc.CSGO_Profile_Rank),
|
3840
|
+
Experience_points_earned_towards_next_rank: isNaN(parseInt(cleanDoc.Experience_points_earned_towards_next_rank)) ? cleanDoc.Experience_points_earned_towards_next_rank : parseInt(cleanDoc.Experience_points_earned_towards_next_rank),
|
3841
|
+
Anti_addiction_online_time: cleanDoc.Anti_addiction_online_time,//'0:11:25'
|
3842
|
+
}
|
3843
|
+
}
|
3844
|
+
|
3845
|
+
async resolveUsers(steamIDs = []) {
|
3846
|
+
return await SteamUser.resolveUsers(steamIDs, this.getCookies())
|
3847
|
+
}
|
3848
|
+
|
3849
|
+
static async resolveUsers(steamIDs = [], cookie) {//steamIDs max = 200
|
3850
|
+
if(typeof steamIDs === 'string') {
|
3851
|
+
steamIDs = [steamIDs]
|
3852
|
+
}
|
3853
|
+
|
3854
|
+
steamIDs = _.uniq(steamIDs)
|
3855
|
+
|
3856
|
+
const {data} = await request({
|
3857
|
+
url: `https://steamcommunity.com/actions/ajaxresolveusers?steamids=${steamIDs.join(',')}`,
|
3858
|
+
headers: {...cookie && {cookie}},
|
3859
|
+
})
|
3860
|
+
|
3861
|
+
if(!Array.isArray(data)) {
|
3862
|
+
return []
|
3863
|
+
}
|
3864
|
+
|
3865
|
+
return data.map(function (player) {
|
3866
|
+
return {
|
3867
|
+
steamID: player.steamid,
|
3868
|
+
accountid: player.accountid,
|
3869
|
+
name: player.persona_name,
|
3870
|
+
realname: player.real_name,
|
3871
|
+
avatarHash: player.avatar_url,
|
3872
|
+
customURL: player.profile_url,
|
3873
|
+
persona_state: player.persona_state,
|
3874
|
+
city: player.city,
|
3875
|
+
state: player.state,
|
3876
|
+
country: player.country,
|
3877
|
+
is_friend: player.is_friend,
|
3878
|
+
friends_in_common: player.friends_in_common,
|
3879
|
+
}
|
3880
|
+
})
|
3881
|
+
}
|
3882
|
+
|
3883
|
+
static GetAvatarURLFromHash(hash, size) {
|
3884
|
+
if(!hash) {
|
3885
|
+
return
|
3886
|
+
}
|
3887
|
+
let strURL = 'https://avatars.akamai.steamstatic.com/' + hash
|
3888
|
+
|
3889
|
+
if(size === 'full') {
|
3890
|
+
strURL += '_full.jpg'
|
3891
|
+
}
|
3892
|
+
else if(size === 'medium') {
|
3893
|
+
strURL += '_medium.jpg'
|
3894
|
+
}
|
3895
|
+
else {
|
3896
|
+
strURL += '.jpg'
|
3897
|
+
}
|
3898
|
+
|
3899
|
+
return strURL
|
3900
|
+
}
|
3901
|
+
|
3902
|
+
static GetAvatarHashFromURL(url) {
|
3903
|
+
if(!url) {
|
3904
|
+
return
|
3905
|
+
}
|
3906
|
+
const suffixes = ['_full.jpg', '_medium.jpg', '.jpg']
|
3907
|
+
|
3908
|
+
for (const suffix of suffixes) {
|
3909
|
+
if(url.includes(suffix)) {
|
3910
|
+
return url.split(suffix)[0].split('/').pop()
|
3911
|
+
}
|
3912
|
+
}
|
3913
|
+
}
|
3914
|
+
|
3915
|
+
static GetAvatarHashFromMultipleURL(urls = []) {
|
3916
|
+
let avatarHash
|
3917
|
+
for (const avatar of urls) {
|
3918
|
+
if((avatarHash = SteamUser.GetAvatarHashFromURL(avatar))) {
|
3919
|
+
break
|
3920
|
+
}
|
3921
|
+
}
|
3922
|
+
return avatarHash
|
3923
|
+
}
|
3924
|
+
|
3925
|
+
static createFriendCode(steamID) {
|
3926
|
+
const accountid = SteamUser.steamID642Miniprofile(steamID)
|
3927
|
+
let acctIdHex = accountid.toString(16)
|
3928
|
+
let friendCode = ''
|
3929
|
+
|
3930
|
+
for (let i = 0; i < acctIdHex.length; i++) {
|
3931
|
+
let char = parseInt(acctIdHex[i], 16)
|
3932
|
+
friendCode += FRIEND_CODE_REPLACEMENTS[char]
|
3933
|
+
}
|
3934
|
+
|
3935
|
+
let dashPos = Math.floor(friendCode.length / 2)
|
3936
|
+
return friendCode.substring(0, dashPos) + '-' + friendCode.substring(dashPos)
|
3937
|
+
}
|
3938
|
+
|
3939
|
+
static parseFriendCode(friendCode) {
|
3940
|
+
friendCode = friendCode.replaceAll('-', '')
|
3941
|
+
let acctIdHex = ''
|
3942
|
+
|
3943
|
+
for (let i = 0; i < friendCode.length; i++) {
|
3944
|
+
let char = friendCode[i]
|
3945
|
+
acctIdHex += FRIEND_CODE_REPLACEMENTS.indexOf(char).toString(16)
|
3946
|
+
}
|
3947
|
+
|
3948
|
+
return new SteamID(`[U:1:${parseInt(acctIdHex, 16)}]`)
|
3949
|
+
};
|
3950
|
+
|
3951
|
+
static _formatString2Int(text) {
|
3952
|
+
const count = parseInt(text?.replaceAll(',', '')?.trim())
|
3953
|
+
return isNaN(count) ? null : count
|
3954
|
+
}
|
3955
|
+
|
3956
|
+
async testFullLanguage(cb) {
|
3957
|
+
const self = this
|
3958
|
+
const initialLanguage = self.Steam_Language
|
3959
|
+
const langs = Object.values(ELanguage)
|
3960
|
+
_.pull(langs, [ELanguage.english])
|
3961
|
+
for (const lang of [ELanguage.english, ...langs]) {
|
3962
|
+
self.setSteamLanguage(lang)
|
3963
|
+
if(cb.constructor.name === 'AsyncFunction') {
|
3964
|
+
// 👇️ this runs
|
3965
|
+
// console.log('✅ function is async')
|
3966
|
+
await cb.call(self, lang)
|
3967
|
+
}
|
3968
|
+
else {
|
3969
|
+
// console.log('⛔️ function is NOT async')
|
3970
|
+
cb.call(self, lang)
|
3971
|
+
}
|
3972
|
+
}
|
3973
|
+
self.setSteamLanguage(initialLanguage)
|
3974
|
+
}
|
3975
|
+
|
3976
|
+
async testNotYetSetupTextList(steamID) {//steamID that not setup
|
3977
|
+
const notYetSetupTexts = []
|
3978
|
+
await this.testFullLanguage(async function (lang) {
|
3979
|
+
const sum = await this.getUserSummaryFromProfile(steamID)
|
3980
|
+
notYetSetupTexts.push(sum.profile_private_info)
|
3981
|
+
})
|
3982
|
+
return _.isEqual(NotYetSetupProfileTextList, notYetSetupTexts)
|
3983
|
+
}
|
3984
|
+
|
3985
|
+
async testPrivateText(steamID) {//steamID that private
|
3986
|
+
const privateTexts = []
|
3987
|
+
await this.testFullLanguage(async function (lang) {
|
3988
|
+
const sum = await this.getUserSummaryFromProfile(steamID)
|
3989
|
+
privateTexts.push(sum.profile_private_info)
|
3990
|
+
})
|
3991
|
+
return _.isEqual(PrivateProfileTextList, privateTexts)
|
3992
|
+
}
|
3993
|
+
|
3994
|
+
async testGameBan(steamID) {//steamID that private
|
3995
|
+
const list = []
|
3996
|
+
await this.testFullLanguage(async function (lang) {
|
3997
|
+
const sum = await this.getUserSummaryFromProfile(steamID)
|
3998
|
+
if(sum.sectionText) {
|
3999
|
+
list.push(sum.sectionText.replace('1 ', '$1').replace('1162 ', '$2'))
|
4000
|
+
// list.push(sum.gameBanFull.replace('1 ', '$1').replace('1162 ', '$2'))
|
4001
|
+
}
|
4002
|
+
})
|
4003
|
+
return list
|
4004
|
+
}
|
4005
|
+
|
4006
|
+
static parseGameBanType(gameBanFull) {
|
4007
|
+
if(Array.isArray(gameBanFull) && !gameBanFull.length) {
|
4008
|
+
return {
|
4009
|
+
isVACBan: 0,
|
4010
|
+
isGameBan: 0,
|
4011
|
+
isTradeBan: 0,
|
4012
|
+
daysSinceLastBan: null,
|
4013
|
+
}
|
4014
|
+
}
|
4015
|
+
|
4016
|
+
const isTradeBan = gameBanFull.some(txt => ECurrentlyTradeBanned.includes(txt)) ? 1 : 0
|
4017
|
+
|
4018
|
+
let isVACBan = 0
|
4019
|
+
if(gameBanFull.some(txt => E1VACBanOnRecord.includes(txt))) {
|
4020
|
+
isVACBan = 1
|
4021
|
+
}
|
4022
|
+
else if(gameBanFull.some(txt => EMultipleVACBansOnRecord.includes(txt))) {
|
4023
|
+
isVACBan = 'Multiple'
|
4024
|
+
}
|
4025
|
+
|
4026
|
+
let isGameBan = 0
|
4027
|
+
if(gameBanFull.some(txt => E1GameBanOnRecord.includes(txt))) {
|
4028
|
+
isGameBan = 1
|
4029
|
+
}
|
4030
|
+
else if(gameBanFull.some(txt => EMultipleGameBansOnRecord.includes(txt))) {
|
4031
|
+
isGameBan = 'Multiple'
|
4032
|
+
}
|
4033
|
+
|
4034
|
+
let daysSinceLastBan = gameBanFull
|
4035
|
+
.map(function (gameBanPart) {
|
4036
|
+
return Object.values(EdaySinceLastBanRegExp)
|
4037
|
+
.map(s => [...gameBanPart.matchAll(new RegExp(s, 'gi'))])
|
4038
|
+
.filter(s => s.length)
|
4039
|
+
})
|
4040
|
+
.filter(s => s.length)
|
4041
|
+
|
4042
|
+
if(Array.isArray(daysSinceLastBan?.[0]?.[0]?.[0])) {
|
4043
|
+
daysSinceLastBan = parseInt(daysSinceLastBan[0][0][0][1])
|
4044
|
+
if(isNaN(daysSinceLastBan)) {
|
4045
|
+
//error
|
4046
|
+
}
|
4047
|
+
}
|
4048
|
+
else {
|
4049
|
+
daysSinceLastBan = null
|
4050
|
+
}
|
4051
|
+
|
4052
|
+
if(!isTradeBan && !isVACBan && !isGameBan) {
|
4053
|
+
console.error('parseGameBanType Error', gameBanFull)
|
4054
|
+
}
|
4055
|
+
|
4056
|
+
return {
|
4057
|
+
isVACBan,
|
4058
|
+
isGameBan,
|
4059
|
+
isTradeBan,
|
4060
|
+
daysSinceLastBan
|
4061
|
+
}
|
4062
|
+
}
|
4063
|
+
}
|
4064
|
+
|
4065
|
+
export default SteamUser
|