diff options
| -rw-r--r-- | README.md | 156 | ||||
| -rw-r--r-- | steamrelationships/sr.py | 90 |
2 files changed, 97 insertions, 149 deletions
| @@ -24,132 +24,80 @@ If using [Poetry](https://python-poetry.org/), all Python dependencies are fetch | |||
| 24 | 24 | ||
| 25 | 1. In a poetry shell, run `poetry add steamrelationships` | 25 | 1. In a poetry shell, run `poetry add steamrelationships` |
| 26 | 2. Import the package `import steamrelationships` | 26 | 2. Import the package `import steamrelationships` |
| 27 | 3. Create an object (example: `steamuser: object = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")`) | 27 | 3. See the documentation on methods & objects |
| 28 | 4. Do a scan (example: `results = steamuser.basic_scan("XXXXXXXXXXXXXXXXX")`) | ||
| 29 | |||
| 30 | Example: | ||
| 31 | |||
| 32 | ```python | ||
| 33 | #!/usr/bin/env -S python3 -i | ||
| 34 | |||
| 35 | # A program that finds the friendliest person in a user's extended friend's list (1 recursive scan) | ||
| 36 | |||
| 37 | import steamrelationships | ||
| 38 | |||
| 39 | if __name__ == "__main__": | ||
| 40 | rq = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", reqsafetybuffer=0.01) | ||
| 41 | testlist = rq.recursivescan("XXXXXXXXXXXXXXXXX", recurselevel=1) | ||
| 42 | del rq | ||
| 43 | |||
| 44 | friendliest: str = "" | ||
| 45 | mostfriends: int = 0 | ||
| 46 | for person in testlist: | ||
| 47 | if len(testlist[person]) >= mostfriends: | ||
| 48 | mostfriends = len(testlist[person]) | ||
| 49 | friendliest = person | ||
| 50 | |||
| 51 | print(f"Largest friends list: {mostfriends}, Owned by: {friendliest}") | ||
| 52 | ``` | ||
| 53 | 28 | ||
| 54 | ## DOCUMENTATION | 29 | ## DOCUMENTATION |
| 55 | 30 | ||
| 56 | ```python | 31 | ### Objects |
| 57 | ''' | ||
| 58 | CONSTANTS: | ||
| 59 | Define a constants object: | ||
| 60 | |||
| 61 | from steamrelationships.constants import _Const | ||
| 62 | CONST = _Const() | ||
| 63 | |||
| 64 | CONST.STEAMAPI_MAXREQ = 100000 | ||
| 65 | # Steam's daily API request limit | ||
| 66 | 32 | ||
| 67 | CONST.DAY_IN_NANO = (8.64 * (10 ** 13)) | 33 | | Object | Full Name | Description | |
| 68 | # The number of nanoseconds in a day | 34 | | :----: | :-------: | :---------- | |
| 35 | | SteamRelationships | steamrelationships.sr.SteamRelationships | A class implementing Steam friends list scanning | | ||
| 36 | | Object | steamrelationships.constants._Const | A class containing constant values used throughout the SteamRelationships Class | | ||
| 69 | 37 | ||
| 70 | CONST.JSON_INDENT = 4 | 38 | ### Constants |
| 71 | # The indent used when dumping a python object to json | ||
| 72 | ''' | ||
| 73 | 39 | ||
| 74 | # Example | 40 | | Name | Value | Description | |
| 75 | import time | 41 | | :-- | ---: | ----------- | |
| 76 | from steamrelationships.constants import _Const | 42 | | STEAMAPI_MAXREQ | 100000 | Steam's daily API request limit | |
| 77 | CONST = _Const() | 43 | | DAY_IN_NANO | 8.64 * (10 ** 13) | The amount of nanoseconds in 24 hours | |
| 78 | 44 | | JSON_INDENT | 4 | The indent used when dumping a Python object to a .json file | | |
| 79 | checktime = time.time_ns() | ||
| 80 | oldtime = int(input("Enter a time since the Unix Epoch in nanoseconds: ")) | ||
| 81 | if checktime - oldtime > CONST.DAY_IN_NANO: | ||
| 82 | print("It has been at least 1 day since the entered time") | ||
| 83 | |||
| 84 | |||
| 85 | |||
| 86 | ''' | ||
| 87 | STEAMRELATIONSHIPS: | ||
| 88 | Create a SteamRelationships object: | ||
| 89 | import steamrelationships | ||
| 90 | steamuser: object = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") | ||
| 91 | |||
| 92 | basicscan - do a basic scan of someone's steam friends | ||
| 93 | PARAMS: | ||
| 94 | (str) steamid64 - The 64 bit steam id of the user you want to scan | ||
| 95 | 45 | ||
| 96 | RETURN VALUES: | 46 | ### `steamrelationships.sr.SteamRelationships()` methods |
| 97 | (dict) EMPTY - There was an error scanning the user's friends list | ||
| 98 | (dict) {steamid64: [friendID1, friendID2, ...]} - A dict with a single key, that of the scanned user, which maps to a list of the users's friends | ||
| 99 | 47 | ||
| 48 | | Function | Params | Return Values | Description | | ||
| 49 | | :------: | :----- | :------------ | :---------- | | ||
| 50 | | basicscan | **`(str) steamid64`** - A 64 bit decimal Steam id | **`(dict)`** A dict with a single key, that of the scanned user, which maps to a list of the users's friends. **Empty on error** | Send a request to Steam's API to retrieve a specified user's friends list | | ||
| 51 | | recursivescan | **`(str) steamid64`** - A 64 bit decimal Steam id; **`(int, Default = 2) recurselevel`** - The number of recursive scans to complete | **`(dict)`** A dict containing the starting steamid, then the friends contained in the original scan with the results of their scan. **Empty on error** | Scan a person's friends list, then scan for their friends' lists. This process repeats for every level of "`recurselevel`" | | ||
| 100 | 52 | ||
| 53 | <details> | ||
| 101 | 54 | ||
| 102 | recursivescan - Scan a user's friends list, then scan their friends as well | 55 | <summary>Private steamrelationships.sr.SteamRelationships() methods</summary> |
| 103 | 56 | ||
| 104 | PARAMS: | 57 | ### Private `steamrelationships.sr.SteamRelationships()` methods |
| 105 | (str) steamid64 - The starting user to scan | ||
| 106 | (int) recurselevel - The number of recursive scans to complete | ||
| 107 | > Note: 0 is equivalent to a basic scan; 1 scans the specified user, then the user's friends; etc. | ||
| 108 | 58 | ||
| 109 | RETURN VALUES: | 59 | | Function | Params | Return Values | Description | |
| 110 | (dict) EMPTY - Some catastrophic error has occured and no scan could be started | 60 | | :------: | :----- | :------------ | :---------- | |
| 111 | (dict) { | 61 | | __readjsonfile | **`(str) filepath`** - Path to json file | **`(dict)`** The contents of the json file. **Empty on error** | Read the specified json file for previous requests. Will create an "empty" json file if the specified file at the `filepath` doesn't exist | |
| 112 | steamid64: | 62 | | __checkrequests | **`(str) filename`** - filepath to requests log | **`(int)`** The number of requests in the last 24 hours. **`-1` on error**, `0` *on too many requests*, and `>1` if a valid number of requests | Check the requests log to make sure Steam's request limit hasn't been passed. Will create a file at `filepath` if it doesn't exist, also will *never go over 100,000 requests*, regardless of what `reqsafetybuffer` is | |
| 113 | [friend1id, friend2id, friend3id, ...], | 63 | | __getFriendsList | **`(str) steamid64`** - A Steam User's id, in the steamid64 format; **`(int, Default = 0) _retries`** - An internal value used to limit the number of retries after a timeout. Increments by one automatically on every timeout | **`(dict)`** The json representation of Steam's response. **Empty on error** | Send a request to the Steam Web API to get a user's friends list | |
| 114 | friend1id: | 64 | | __parseFriendsList | **`(dict) friendsdict`** - The return value of `__getFriendsList` | **`(list)`** The steamid64's of a user's friends. **Empty on error** | Parse a response from Steam and extract a user's friend's Steam IDs | |
| 115 | [other_friend, other_friend, ...], | ||
| 116 | friend2id: | ||
| 117 | [other_friend, other_friend, ...], | ||
| 118 | friend3id: | ||
| 119 | [other_friend, other_friend, ...], | ||
| 120 | ... | ||
| 121 | } | ||
| 122 | 65 | ||
| 123 | - A dict containing the starting steamid, then the friends contained in the original scan with the results of their scan | 66 | </details> |
| 124 | 67 | ||
| 125 | NOTE: | 68 | Example program |
| 126 | Please do not use a value greater than 3. While theoretically any value works, due to the exponential nature of friendship relations, you will very quickly spam Steam with tens of thousands of requests. If this concept is unfamiliar to you, please take a quick glance at the Wikipedia page for "six degress of separation": https://en.wikipedia.org/wiki/Six_degrees_of_separation | ||
| 127 | 69 | ||
| 128 | TLDR: recursivescan is exponential and you will reach 100,000 requests very quickly if you recurse greater than 3 | 70 | ```python |
| 129 | ''' | 71 | #!/usr/bin/env -S python3 -i |
| 130 | 72 | ||
| 131 | # Example | ||
| 132 | import steamrelationships | 73 | import steamrelationships |
| 74 | from steamrelationships.constants import _Const | ||
| 75 | CONST = _Const() | ||
| 76 | |||
| 77 | if __name__ == "__main__": | ||
| 78 | print(f"Constants:\n\t> Max API Requests per Day: {CONST.STEAMAPI_MAXREQ}\n\t> Number of Nanoseconds In a Day: {CONST.DAY_IN_NANO}\n\t> .json File Indent: {CONST.JSON_INDENT}") | ||
| 133 | 79 | ||
| 134 | steamuser: object = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") | 80 | # Replace the XXXX's with your dev api key |
| 81 | steamuser: object = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", reqsafetybuffer=0.01) | ||
| 135 | 82 | ||
| 136 | bigscan: dict = steamuser.recursivescan("XXXXXXXXXXXXXXXXX") | 83 | # Replace the XXXX's with the steam id of the guy you want to scan |
| 137 | littlescan: dict = steamuser.basicscan("XXXXXXXXXXXXXXXXX") | 84 | bigscan: dict = steamuser.recursivescan("XXXXXXXXXXXXXXXXX", recurselevel=1) |
| 85 | littlescan: dict = steamuser.basicscan("XXXXXXXXXXXXXXXXX") | ||
| 138 | 86 | ||
| 139 | del steamuser | 87 | del steamuser |
| 140 | 88 | ||
| 141 | print(f'Original scanned user: {list(littlescan.keys())[0]}\nOriginal Friends: {littlescan[list(littlescan.keys())[0]]}') | 89 | print(f'Original scanned user: {list(littlescan.keys())[0]}\nOriginal Friends: {littlescan[list(littlescan.keys())[0]]}') |
| 142 | 90 | ||
| 143 | totalscanned: int = 0 | 91 | totalscanned: int = 0 |
| 144 | alreadyscanned: list = [] | 92 | alreadyscanned: list = [] |
| 145 | for scanned in bigscan.keys(): | 93 | for scanned in bigscan.keys(): |
| 146 | totalscanned += 1 | 94 | totalscanned += 1 |
| 147 | alreadyscanned.append(scanned) | 95 | alreadyscanned.append(scanned) |
| 148 | 96 | ||
| 149 | for friend in bigscan[scanned]: | 97 | for friend in bigscan[scanned]: |
| 150 | if friend not in alreadyscanned: | 98 | if friend not in alreadyscanned: |
| 151 | totalscanned += 1 | 99 | totalscanned += 1 |
| 152 | alreadyscanned.append(friend) | 100 | alreadyscanned.append(friend) |
| 153 | 101 | ||
| 154 | print(f"Total scanned: {totalscanned}") | 102 | print(f"Total users found: {totalscanned}") |
| 155 | ``` | 103 | ``` |
diff --git a/steamrelationships/sr.py b/steamrelationships/sr.py index 28b6b16..63122b4 100644 --- a/steamrelationships/sr.py +++ b/steamrelationships/sr.py | |||
| @@ -8,14 +8,14 @@ CONST = _Const() | |||
| 8 | 8 | ||
| 9 | class SteamRelationships: | 9 | class SteamRelationships: |
| 10 | """A class that handles the querring of Steam's web api to request a user's friends list""" | 10 | """A class that handles the querring of Steam's web api to request a user's friends list""" |
| 11 | 11 | ||
| 12 | session: object = requests.Session() # Session object so repeated querries to steam's api use the same TCP connection | 12 | session: object = requests.Session() # Session object so repeated querries to steam's api use the same TCP connection |
| 13 | scanlist: dict = {} # To be populated by scan functions | 13 | scanlist: dict = {} # To be populated by scan functions |
| 14 | 14 | ||
| 15 | def __init__(self, webapikey: str, timeout: int = 30, timeout_retries: int = 5, reqdelay: float = 0.5, delayrand: int = 25, reqsafetybuffer: float = 0.9, reqjson: str = "requests.json") -> None: | 15 | def __init__(self, webapikey: str, timeout: int = 30, timeout_retries: int = 5, reqdelay: float = 0.5, delayrand: int = 25, reqsafetybuffer: float = 0.9, reqjson: str = "requests.json") -> None: |
| 16 | """ | 16 | """ |
| 17 | (str) webapikey - A Steam "web api key" for grabbing friends lists (get one at https://steamcommunity.com/dev/apikey) | 17 | (str) webapikey - A Steam "web api key" for grabbing friends lists (get one at https://steamcommunity.com/dev/apikey) |
| 18 | 18 | ||
| 19 | (int) timeout (Default: 30) - The time in seconds to wait for a response from Steam before timing out | 19 | (int) timeout (Default: 30) - The time in seconds to wait for a response from Steam before timing out |
| 20 | (int) timeout_retries (Default: 5) - The number of times to retry a scan after a timeout | 20 | (int) timeout_retries (Default: 5) - The number of times to retry a scan after a timeout |
| 21 | (float) reqdelay (Default: 0.5) - The base amount of seconds to wait after each scan (to lessen the load on Steam's servers) | 21 | (float) reqdelay (Default: 0.5) - The base amount of seconds to wait after each scan (to lessen the load on Steam's servers) |
| @@ -40,14 +40,14 @@ class SteamRelationships: | |||
| 40 | def __str__(self) -> str: | 40 | def __str__(self) -> str: |
| 41 | return f"Vals:\n\twebapikey: {len(self.webapikey) > 0} (Actual value ommitted for security)\n\n\tTimeout: {self.timeout}\n\tTimeout Retries: {self.timeout_retries}\n\tRequest Delay: {self.reqdelay}\n\tRequest Delay Randomness Factor: +/- {self.delayrand}%\n\tRequest Safety Buffer: {self.reqsafetybuffer} ({self.reqsafetybuffer * CONST.STEAMAPI_MAXREQ} out of {CONST.STEAMAPI_MAXREQ} max requests)\n\tRequests Log Filepath: \"{self.reqjson}\"\n\n\tMost Recent Scan: {self.scanlist}" | 41 | return f"Vals:\n\twebapikey: {len(self.webapikey) > 0} (Actual value ommitted for security)\n\n\tTimeout: {self.timeout}\n\tTimeout Retries: {self.timeout_retries}\n\tRequest Delay: {self.reqdelay}\n\tRequest Delay Randomness Factor: +/- {self.delayrand}%\n\tRequest Safety Buffer: {self.reqsafetybuffer} ({self.reqsafetybuffer * CONST.STEAMAPI_MAXREQ} out of {CONST.STEAMAPI_MAXREQ} max requests)\n\tRequests Log Filepath: \"{self.reqjson}\"\n\n\tMost Recent Scan: {self.scanlist}" |
| 42 | 42 | ||
| 43 | def _readjsonfile(self, filepath: str = "") -> dict: | 43 | def __readjsonfile(self, filepath: str = "") -> dict: |
| 44 | """ | 44 | """ |
| 45 | _readjsonfile(self, filepath: str = "") -> dict: Read the specified json file for previous requests | 45 | __readjsonfile(self, filepath: str = "") -> dict: Read the specified json file for previous requests |
| 46 | filepath: Path to json file | 46 | filepath: Path to json file |
| 47 | 47 | ||
| 48 | dict (return): The contents of the json file. Empty on error | 48 | dict (return): The contents of the json file. Empty on error |
| 49 | 49 | ||
| 50 | _readjsonfile will create an "empty" json file if the specified file at the filepath doesn't exist | 50 | __readjsonfile will create an "empty" json file if the specified file at the filepath doesn't exist |
| 51 | """ | 51 | """ |
| 52 | if not filepath: | 52 | if not filepath: |
| 53 | filepath = self.reqjson | 53 | filepath = self.reqjson |
| @@ -63,31 +63,31 @@ class SteamRelationships: | |||
| 63 | 63 | ||
| 64 | # If the file does not exist, create one and slap an empty list in it | 64 | # If the file does not exist, create one and slap an empty list in it |
| 65 | except FileNotFoundError: | 65 | except FileNotFoundError: |
| 66 | print(f"[_readjsonfile] File {filepath} does not exist. Generating empty json file...") | 66 | print(f"[__readjsonfile] File {filepath} does not exist. Generating empty json file...") |
| 67 | try: | 67 | try: |
| 68 | with open(filepath, "w+") as newfile: | 68 | with open(filepath, "w+") as newfile: |
| 69 | json.dump({time.time_ns(): [0, []]}, newfile, indent=CONST.JSON_INDENT) | 69 | json.dump({time.time_ns(): [0, []]}, newfile, indent=CONST.JSON_INDENT) |
| 70 | newfile.close() | 70 | newfile.close() |
| 71 | 71 | ||
| 72 | return self._readjsonfile(filepath) | 72 | return self.__readjsonfile(filepath) |
| 73 | 73 | ||
| 74 | except Exception as e: | 74 | except Exception as e: |
| 75 | print(f"[_readjsonfile] Couldn't create new file ({e})") | 75 | print(f"[__readjsonfile] Couldn't create new file ({e})") |
| 76 | return {} | 76 | return {} |
| 77 | 77 | ||
| 78 | except Exception as e: | 78 | except Exception as e: |
| 79 | print(f"[_readjsonfile] Other unknown error occured ({e})") | 79 | print(f"[__readjsonfile] Other unknown error occured ({e})") |
| 80 | return {} | 80 | return {} |
| 81 | 81 | ||
| 82 | return final | 82 | return final |
| 83 | 83 | ||
| 84 | def _checkrequests(self, filename: str = "") -> int: | 84 | def __checkrequests(self, filename: str = "") -> int: |
| 85 | """ | 85 | """ |
| 86 | _checkrequests(self, filename: str = "") -> int: Check the requests log to make sure Steam's request limit hasn't been passed | 86 | __checkrequests(self, filename: str = "") -> int: Check the requests log to make sure Steam's request limit hasn't been passed |
| 87 | filename: filepath to requests log | 87 | filename: filepath to requests log |
| 88 | int (return): The number of requests in the last 24 hours. -1 on error, 0 on too many requests, and >1 if a valid number of requests | 88 | int (return): The number of requests in the last 24 hours. -1 on error, 0 on too many requests, and >1 if a valid number of requests |
| 89 | 89 | ||
| 90 | _checkrequests will create a file at filepath if it doesn't exist. It will also never go over 100,000 requests, regardless of what reqsafetybuffer is | 90 | __checkrequests will create a file at filepath if it doesn't exist. It will also never go over 100,000 requests, regardless of what reqsafetybuffer is |
| 91 | """ | 91 | """ |
| 92 | if not filename: | 92 | if not filename: |
| 93 | filename = self.reqjson | 93 | filename = self.reqjson |
| @@ -95,10 +95,10 @@ class SteamRelationships: | |||
| 95 | # Get the contents of the specified file | 95 | # Get the contents of the specified file |
| 96 | jsoncontents: dict = {} | 96 | jsoncontents: dict = {} |
| 97 | try: | 97 | try: |
| 98 | jsoncontents = self._readjsonfile(filename) | 98 | jsoncontents = self.__readjsonfile(filename) |
| 99 | 99 | ||
| 100 | except Exception as e: | 100 | except Exception as e: |
| 101 | print(f"[_checkrequests] Could not get the contents of file \"{filename}\" ({e})") | 101 | print(f"[__checkrequests] Could not get the contents of file \"{filename}\" ({e})") |
| 102 | return -1 | 102 | return -1 |
| 103 | 103 | ||
| 104 | # Check the current date. If over 1 day since last entry, add a new entry. Otherwise, edit the current day's entry [note, 1 day in nanoseconds = (8.64 * (10 ** 13)) ] | 104 | # Check the current date. If over 1 day since last entry, add a new entry. Otherwise, edit the current day's entry [note, 1 day in nanoseconds = (8.64 * (10 ** 13)) ] |
| @@ -114,7 +114,7 @@ class SteamRelationships: | |||
| 114 | jsoncontents[list(jsoncontents.keys())[-1]][1].append(checktime) | 114 | jsoncontents[list(jsoncontents.keys())[-1]][1].append(checktime) |
| 115 | 115 | ||
| 116 | else: | 116 | else: |
| 117 | print(f"[_checkrequests] Daily request limit reached ({currentreqs}/{CONST.STEAMAPI_MAXREQ * self.reqsafetybuffer}). Please try again tomorrow, or increase \"reqsafetybuffer\" (currently: {self.reqsafetybuffer})") | 117 | print(f"[__checkrequests] Daily request limit reached ({currentreqs}/{CONST.STEAMAPI_MAXREQ * self.reqsafetybuffer}). Please try again tomorrow, or increase \"reqsafetybuffer\" (currently: {self.reqsafetybuffer})") |
| 118 | return 0 | 118 | return 0 |
| 119 | 119 | ||
| 120 | # Update the json file | 120 | # Update the json file |
| @@ -124,28 +124,28 @@ class SteamRelationships: | |||
| 124 | jsonfile.close() | 124 | jsonfile.close() |
| 125 | 125 | ||
| 126 | except Exception as e: | 126 | except Exception as e: |
| 127 | print(f"[_checkrequests] Could not update json file ({e})") | 127 | print(f"[__checkrequests] Could not update json file ({e})") |
| 128 | return -1 | 128 | return -1 |
| 129 | 129 | ||
| 130 | return jsoncontents[list(jsoncontents.keys())[-1]][0] | 130 | return jsoncontents[list(jsoncontents.keys())[-1]][0] |
| 131 | 131 | ||
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | def _getFriendsList(self, steamid64: str, _retries: int = 0) -> dict: | 134 | def __getFriendsList(self, steamid64: str, _retries: int = 0) -> dict: |
| 135 | """ | 135 | """ |
| 136 | _getFriendsList(self, steamid64: str, _retries: int = 0) -> dict: Send a request to the Steam Web API to get a user's friends list | 136 | __getFriendsList(self, steamid64: str, _retries: int = 0) -> dict: Send a request to the Steam Web API to get a user's friends list |
| 137 | steamid64: A Steam User's id, in the steamid64 format | 137 | steamid64: A Steam User's id, in the steamid64 format |
| 138 | _retries: An internal value used to limit the number of retries after a timeout. Increments by one automatically on every timeout | 138 | _retries: An internal value used to limit the number of retries after a timeout. Increments by one automatically on every timeout |
| 139 | 139 | ||
| 140 | dict (return): The json representation of Steam's response. Empty on error | 140 | dict (return): The json representation of Steam's response. Empty on error |
| 141 | """ | 141 | """ |
| 142 | if not steamid64: | 142 | if not steamid64: |
| 143 | print("[_getFriendsList] No steamid64 given") | 143 | print("[__getFriendsList] No steamid64 given") |
| 144 | return {} | 144 | return {} |
| 145 | 145 | ||
| 146 | # Make sure we haven't gone over steam's daily max | 146 | # Make sure we haven't gone over steam's daily max |
| 147 | if self._checkrequests() == 0: | 147 | if self.__checkrequests() == 0: |
| 148 | print("[_getFriendsList] Max requests reached, refusing to contact steam") | 148 | print("[__getFriendsList] Max requests reached, refusing to contact steam") |
| 149 | return {} | 149 | return {} |
| 150 | 150 | ||
| 151 | url: str = "https://api.steampowered.com/ISteamUser/GetFriendList/v0001/" | 151 | url: str = "https://api.steampowered.com/ISteamUser/GetFriendList/v0001/" |
| @@ -157,24 +157,24 @@ class SteamRelationships: | |||
| 157 | result = self.session.get(url, params=options, timeout=self.timeout) | 157 | result = self.session.get(url, params=options, timeout=self.timeout) |
| 158 | 158 | ||
| 159 | except requests.exceptions.Timeout: | 159 | except requests.exceptions.Timeout: |
| 160 | print(f"[_getFriendsList] Request timed out (No response for {self.timeout} seconds)") | 160 | print(f"[__getFriendsList] Request timed out (No response for {self.timeout} seconds)") |
| 161 | if _retries <= self.timeout_retries: | 161 | if _retries <= self.timeout_retries: |
| 162 | print(f"[_getFriendsList] Retrying request... (Attempt {_retries}/{self.timeout_retries})") | 162 | print(f"[__getFriendsList] Retrying request... (Attempt {_retries}/{self.timeout_retries})") |
| 163 | return self._getFriendsList(steamid64, _retries + 1) | 163 | return self.__getFriendsList(steamid64, _retries + 1) |
| 164 | 164 | ||
| 165 | print("[_getFriendsList] Retry limit reached") | 165 | print("[__getFriendsList] Retry limit reached") |
| 166 | return {} | 166 | return {} |
| 167 | 167 | ||
| 168 | except Exception as e: | 168 | except Exception as e: |
| 169 | print(f"[_getFriendsList] Other error in contacting steam ({e})") | 169 | print(f"[__getFriendsList] Other error in contacting steam ({e})") |
| 170 | return {} | 170 | return {} |
| 171 | 171 | ||
| 172 | # Error out on request error | 172 | # Error out on request error |
| 173 | if result.status_code != requests.codes.ok: | 173 | if result.status_code != requests.codes.ok: |
| 174 | print(f"[_getFriendsList] Got bad status code (Requested id: {steamid64}, status: {result.status_code})", end="") | 174 | print(f"[__getFriendsList] Got bad status code (Requested id: {steamid64}, status: {result.status_code})", end="") |
| 175 | if result.status_code == 401: # Steam returns a 401 on profiles with private friends lists | 175 | if result.status_code == 401: # Steam returns a 401 on profiles with private friends lists |
| 176 | print(f". It is likely that the requested id has a private profile / private friends list", end="") | 176 | print(f". It is likely that the requested id has a private profile / private friends list", end="") |
| 177 | 177 | ||
| 178 | print("\n", end="") | 178 | print("\n", end="") |
| 179 | return {} | 179 | return {} |
| 180 | 180 | ||
| @@ -184,25 +184,25 @@ class SteamRelationships: | |||
| 184 | resultjson = result.json() | 184 | resultjson = result.json() |
| 185 | 185 | ||
| 186 | except requests.exceptions.JSONDecodeError: | 186 | except requests.exceptions.JSONDecodeError: |
| 187 | print("[_getFriendsList] Could not decode json response for some reason") | 187 | print("[__getFriendsList] Could not decode json response for some reason") |
| 188 | return {} | 188 | return {} |
| 189 | 189 | ||
| 190 | except Exception as e: | 190 | except Exception as e: |
| 191 | print(f"[_getFriendsList] Unknown error in getting json response ({e})") | 191 | print(f"[__getFriendsList] Unknown error in getting json response ({e})") |
| 192 | return {} | 192 | return {} |
| 193 | 193 | ||
| 194 | return resultjson | 194 | return resultjson |
| 195 | 195 | ||
| 196 | def _parseFriendsList(self, friendsdict: dict) -> list: | 196 | def __parseFriendsList(self, friendsdict: dict) -> list: |
| 197 | """ | 197 | """ |
| 198 | _parseFriendsList(self, friendsdict: dict) -> list: Parse a response from Steam and extract a user's friend's Steam IDs | 198 | __parseFriendsList(self, friendsdict: dict) -> list: Parse a response from Steam and extract a user's friend's Steam IDs |
| 199 | friendsdict: The return value of _getFriendsList | 199 | friendsdict: The return value of __getFriendsList |
| 200 | 200 | ||
| 201 | list (return): The steamid64's of a user's friends. Empty on error | 201 | list (return): The steamid64's of a user's friends. Empty on error |
| 202 | """ | 202 | """ |
| 203 | 203 | ||
| 204 | if not friendsdict: | 204 | if not friendsdict: |
| 205 | print("[_parseFriendsList] Empty friends dict given") | 205 | print("[__parseFriendsList] Empty friends dict given") |
| 206 | return [] | 206 | return [] |
| 207 | 207 | ||
| 208 | 208 | ||
| @@ -212,7 +212,7 @@ class SteamRelationships: | |||
| 212 | people.append(f'{friend["steamid"]}') | 212 | people.append(f'{friend["steamid"]}') |
| 213 | 213 | ||
| 214 | except Exception as e: | 214 | except Exception as e: |
| 215 | print("[_parseFriendsList] Error parsing friendsdict ({e})") | 215 | print("[__parseFriendsList] Error parsing friendsdict ({e})") |
| 216 | people.clear() | 216 | people.clear() |
| 217 | 217 | ||
| 218 | return people | 218 | return people |
| @@ -229,7 +229,7 @@ class SteamRelationships: | |||
| 229 | (dict) {steamid64: [friendID1, friendID2, ...]} - A dict with a single key, that of the scanned user, which maps to a list of the users's friends | 229 | (dict) {steamid64: [friendID1, friendID2, ...]} - A dict with a single key, that of the scanned user, which maps to a list of the users's friends |
| 230 | 230 | ||
| 231 | ''' | 231 | ''' |
| 232 | self.scanlist = {steamid64: self._parseFriendsList(self._getFriendsList(steamid64))} | 232 | self.scanlist = {steamid64: self.__parseFriendsList(self.__getFriendsList(steamid64))} |
| 233 | return self.scanlist | 233 | return self.scanlist |
| 234 | 234 | ||
| 235 | def recursivescan(self, steamid64: str, recurselevel: int = 2) -> dict: | 235 | def recursivescan(self, steamid64: str, recurselevel: int = 2) -> dict: |
| @@ -244,12 +244,12 @@ class SteamRelationships: | |||
| 244 | RETURN VALUES: | 244 | RETURN VALUES: |
| 245 | (dict) EMPTY - Some catastrophic error has occured and no scan could be started | 245 | (dict) EMPTY - Some catastrophic error has occured and no scan could be started |
| 246 | (dict) { | 246 | (dict) { |
| 247 | steamid64: | 247 | steamid64: |
| 248 | [friend1id, friend2id, friend3id, ...], | 248 | [friend1id, friend2id, friend3id, ...], |
| 249 | friend1id: | 249 | friend1id: |
| 250 | [other_friend, other_friend, ...], | 250 | [other_friend, other_friend, ...], |
| 251 | friend2id: | 251 | friend2id: |
| 252 | [other_friend, other_friend, ...], | 252 | [other_friend, other_friend, ...], |
| 253 | friend3id: | 253 | friend3id: |
| 254 | [other_friend, other_friend, ...], | 254 | [other_friend, other_friend, ...], |
| 255 | ... | 255 | ... |
| @@ -276,7 +276,7 @@ class SteamRelationships: | |||
| 276 | 276 | ||
| 277 | sleepytime: float = abs(random.randrange(100 - self.delayrand, 100 + self.delayrand) / 100 * self.reqdelay) | 277 | sleepytime: float = abs(random.randrange(100 - self.delayrand, 100 + self.delayrand) / 100 * self.reqdelay) |
| 278 | time.sleep(sleepytime) | 278 | time.sleep(sleepytime) |
| 279 | 279 | ||
| 280 | testlist.update(tempdict) | 280 | testlist.update(tempdict) |
| 281 | tempdict.clear() | 281 | tempdict.clear() |
| 282 | 282 | ||
