add --getseed flag (#74)

This commit is contained in:
eli fessler
2022-11-19 06:51:50 -10:00
parent 4d81806f74
commit 54bd9a3be7
4 changed files with 95 additions and 18 deletions

View File

@@ -11,7 +11,8 @@ Looking to track your _Splatoon 2_ gameplay? See **[splatnet2statink](https://gi
- [x] Full automation of SplatNet token generation via user log-in
- [x] Ability to parse & upload complete battle/job stats to stat.ink ([example profile](https://stat.ink/@frozenpandaman/spl3))
- [x] Monitoring for new results in real-time & checking for missing/unuploaded results
- [x] Flag to black out other players' names from results
- [x] Flag to remove other players' names from results
- [x] File exporting function for use with Lean's [gear & Shell-Out Machine seed checker](https://leanny.github.io/splat3seedchecker/)
- [x] Support for all available game languages
- [x] Modular design to support [IkaLog3](https://github.com/hasegaw/IkaLog3) and other tools
@@ -23,7 +24,7 @@ Looking to track your _Splatoon 2_ gameplay? See **[splatnet2statink](https://gi
## Usage 🐙
```
$ python s3s.py [-M [N]] [-r] [-nsr | -osr] [--blackout]
$ python s3s.py [-M [N]] [-r] [-nsr | -osr] [--blackout] [--getseed]
```
The `-M` flag runs the script in monitoring mode, uploading new battles/jobs as you play, checking for new results every `N` seconds; if no `N` is provided, it defaults to 300 (5 minutes).
@@ -34,7 +35,9 @@ The `-nsr` flag makes Salmon Run jobs **not** be monitored/uploaded. Use this if
The `-osr` flag, conversely, makes **only** Salmon Run jobs be monitored/uploaded. Use this if you're playing at Grizzco only.
The `--blackout` flag blacks out other players' names in uploaded scoreboard data.
The `--blackout` flag removes other players' names from uploaded scoreboard data.
The `--getseed` flag exports a file which can be uploaded to Lean's [gear & Shell-Out Machine seed checker](https://leanny.github.io/splat3seedchecker/).
Arguments for advanced usage (e.g. locally exporting data to JSON files) can be viewed using `--help`.

View File

@@ -1,4 +1,5 @@
beautifulsoup4
mmh3
msgpack_python
packaging
requests

84
s3s.py
View File

@@ -5,11 +5,11 @@
# License: GPLv3
import argparse, base64, datetime, json, os, shutil, re, requests, sys, time, uuid
import msgpack
import mmh3, msgpack
from packaging import version
import iksm, utils
A_VERSION = "0.1.16"
A_VERSION = "0.1.17"
DEBUG = False
@@ -1225,6 +1225,67 @@ class SquidProgress:
sys.stdout.flush()
def export_seed_json(skipprefetch=False):
'''Export a JSON file for use with Lean's seed checker at https://leanny.github.io/splat3seedchecker/.'''
if not skipprefetch:
prefetch_checks(printout=True)
sha = utils.translate_rid["MyOutfitCommonDataEquipmentsQuery"]
outfit_post = requests.post(utils.GRAPHQL_URL, data=utils.gen_graphql_body(sha),
headers=headbutt(), cookies=dict(_gtoken=GTOKEN))
sha = utils.translate_rid["LatestBattleHistoriesQuery"]
history_post = requests.post(utils.GRAPHQL_URL, data=utils.gen_graphql_body(sha),
headers=headbutt(), cookies=dict(_gtoken=GTOKEN))
if outfit_post.status_code != 200 or history_post.status_code != 200:
print("Could not reach SplatNet 3. Exiting.")
sys.exit(1)
try:
outfit = json.loads(outfit_post.text)
history = json.loads(history_post.text)
except:
print("Ill-formatted JSON file received. Exiting.")
sys.exit(1)
try:
pid = history["data"]["latestBattleHistories"]["historyGroupsOnlyFirst"]["nodes"][0]["historyDetails"]["nodes"][0]["player"]["id"]
# VsPlayer-u-<20 char long player id>:RECENT:<YYYYMMDD>T<HHMMSS>_<UUID>:u-<same player id as earlier>
s = utils.b64d(pid)
r = s.split(":")[-1]
except KeyError: # no recent battles (mr. grizz is pleased)
try:
sha = utils.translate_rid["CoopHistoryQuery"]
history_post = requests.post(utils.GRAPHQL_URL, data=utils.gen_graphql_body(sha),
headers=headbutt(), cookies=dict(_gtoken=GTOKEN))
if history_post.status_code != 200:
print("Could not reach SplatNet 3. Exiting.")
sys.exit(1)
try:
history = json.loads(history_post.text)
except:
print("Ill-formatted JSON file received. Exiting.")
sys.exit(1)
pid = history["data"]["coopResult"]["historyGroupsOnlyFirst"]["nodes"][0]["historyDetails"]["nodes"][0]["id"]
# CoopHistoryDetail-u-<20 char long player id>:<YYYYMMDD>T<HHMMSS>_<UUID>
s = utils.b64d(pid)
r = s.split(":")[0].replace("CoopHistoryDetail-", "")
except KeyError:
r = ""
h = mmh3.hash(r)&0xFFFFFFFF # make positive
key = base64.b64encode(bytes([k^(h&0xFF) for k in bytes(r, "utf-8")]))
t = int(time.time())
with open(os.path.join(os.getcwd(), f"gear_{t}.json"), "x") as fout:
json.dump({"key": key.decode("utf-8"), "h": h, "timestamp": t, "gear": outfit}, fout)
print(f"gear_{t}.json has been exported.")
def parse_arguments():
'''Setup for command-line options.'''
@@ -1235,17 +1296,19 @@ def parse_arguments():
parser.add_argument("-r", required=False, action="store_true",
help="retroactively post unuploaded battles/jobs")
srgroup.add_argument("-nsr", required=False, action="store_true",
help="do not check for Salmon Run jobs")
help="do not check for Salmon Run jobs")
srgroup.add_argument("-osr", required=False, action="store_true",
help="only check for Salmon Run jobs")
help="only check for Salmon Run jobs")
parser.add_argument("--blackout", required=False, action="store_true",
help="black out names in uploaded scoreboard data")
help="remove player names from uploaded scoreboard data")
parser.add_argument("-o", required=False, action="store_true",
help="export all possible results to local files")
parser.add_argument("-i", dest="file", nargs=2, required=False,
help="upload local results; use `-i results.json overview.json`")
parser.add_argument("-t", required=False, action="store_true",
help="dry run for testing (won't post to stat.ink)")
parser.add_argument("--getseed", required=False, action="store_true",
help="export JSON for gear & Shell-Out Machine seed checker")
parser.add_argument("--skipprefetch", required=False, action="store_true", help=argparse.SUPPRESS)
return parser.parse_args()
@@ -1271,6 +1334,7 @@ def main():
only_ink = parser_result.nsr # ink battles ONLY
only_salmon = parser_result.osr # salmon run ONLY
blackout = parser_result.blackout
getseed = parser_result.getseed
# testing/dev stuff
test_run = parser_result.t # send to stat.ink as dry run
@@ -1280,7 +1344,15 @@ def main():
# i/o checks
############
if only_ink and only_salmon:
if getseed and len(sys.argv) > 2 and "--skipprefetch" not in sys.argv:
print("Cannot use --getseed with other arguments. Exiting.")
sys.exit(0)
elif getseed:
export_seed_json(skipprefetch)
sys.exit(0)
elif only_ink and only_salmon:
print("That doesn't make any sense! :) Exiting.")
sys.exit(0)

View File

@@ -20,14 +20,15 @@ SUPPORTED_KEYS = [
# SHA256 hash database for SplatNet 3 GraphQL queries
# full list: https://github.com/samuelthomas2774/nxapi/discussions/11#discussioncomment-3614603
translate_rid = {
'HomeQuery': 'dba47124d5ec3090c97ba17db5d2f4b3', # blank vars
'LatestBattleHistoriesQuery': '7d8b560e31617e981cf7c8aa1ca13a00', # INK / blank vars - query1
'RegularBattleHistoriesQuery': 'f6e7e0277e03ff14edfef3b41f70cd33', # INK / blank vars - query1
'BankaraBattleHistoriesQuery': 'c1553ac75de0a3ea497cdbafaa93e95b', # INK / blank vars - query1
'PrivateBattleHistoriesQuery': '38e0529de8bc77189504d26c7a14e0b8', # INK / blank vars - query1
'VsHistoryDetailQuery': '2b085984f729cd51938fc069ceef784a', # INK / req "vsResultId" - query2
'CoopHistoryQuery': '817618ce39bcf5570f52a97d73301b30', # SR / blank vars - query1
'CoopHistoryDetailQuery': 'f3799a033f0a7ad4b1b396f9a3bafb1e' # SR / req "coopHistoryDetailId" - query2
'HomeQuery': 'dba47124d5ec3090c97ba17db5d2f4b3', # blank vars
'LatestBattleHistoriesQuery': '7d8b560e31617e981cf7c8aa1ca13a00', # INK / blank vars - query1
'RegularBattleHistoriesQuery': 'f6e7e0277e03ff14edfef3b41f70cd33', # INK / blank vars - query1
'BankaraBattleHistoriesQuery': 'c1553ac75de0a3ea497cdbafaa93e95b', # INK / blank vars - query1
'PrivateBattleHistoriesQuery': '38e0529de8bc77189504d26c7a14e0b8', # INK / blank vars - query1
'VsHistoryDetailQuery': '2b085984f729cd51938fc069ceef784a', # INK / req "vsResultId" - query2
'CoopHistoryQuery': '817618ce39bcf5570f52a97d73301b30', # SR / blank vars - query1
'CoopHistoryDetailQuery': 'f3799a033f0a7ad4b1b396f9a3bafb1e', # SR / req "coopHistoryDetailId" - query2
'MyOutfitCommonDataEquipmentsQuery': 'd29cd0c2b5e6bac90dd5b817914832f8' # for Lean's seed checker
}
@@ -94,7 +95,7 @@ def b64d(string):
if len(thing_id) == 5 and thing_id[:1] == "2" and thing_id[-3:] == "900": # grizzco weapon ID from a hacker
return ""
if thing_id[:15] == "VsHistoryDetail" or thing_id[:17] == "CoopHistoryDetail":
if thing_id[:15] == "VsHistoryDetail" or thing_id[:17] == "CoopHistoryDetail" or thing_id[:8] == "VsPlayer":
return thing_id # string
else:
return int(thing_id) # integer