Last active
December 7, 2018 15:40
-
-
Save thurask/0da26d6733923807f204262c9d952860 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""Check some popular TS4 mods for updates.""" | |
import argparse | |
import io | |
import os | |
import platform | |
import re | |
import string | |
import sys | |
import tempfile | |
import zipfile | |
import bs4 # pip install bs4 | |
import requests # pip install requests | |
import uncompyle6 # pip install uncompyle6 | |
try: | |
import unpyc3 # https://github.com/andrew-tavera/unpyc37 | |
except (ImportError, AttributeError): | |
UNPYC = False | |
else: | |
UNPYC = True | |
GISTURL = "https://gist.github.com/thurask/0da26d6733923807f204262c9d952860" | |
BMDURL = "https://basementalcc.com/download/" | |
MCURL = "https://deaderpool-mccc.com/main.bundle.js" | |
WWURL = "https://wickedwhimsmod.com/download/" | |
WPURL = "https://www.loverslab.com/files/file/5002-nisa%E2%80%99s-wicked-perversions/" | |
PATCHURL = "https://help.ea.com/en-us/help/the-sims/the-sims-4/the-sims-4-updates/" | |
TS4FOLDER = os.path.join(os.path.expanduser("~"), "Documents", "Electronic Arts", "The Sims 4") | |
def get_mod_packages(filtername): | |
"""Get mod package paths.""" | |
rootmod = os.path.join(TS4FOLDER, "Mods") | |
results = [] | |
for root, _, files in os.walk(rootmod): | |
for filex in files: | |
if filex.endswith(filtername): | |
results.append(os.path.join(root, filex)) | |
return results | |
def decomp_function(infile, dummyio, unpyc=False): | |
"""Decompiler function of choice.""" | |
if unpyc: | |
decomp = unpyc3.decompile(infile) | |
print(decomp, file=dummyio) | |
dfinal = dummyio.getvalue() | |
else: | |
decomp = uncompyle6.decompile_file(infile, dummyio)[0] | |
dfinal = decomp.text | |
return dfinal | |
def zip_opener(zipf, pyoname, tmppath): | |
"""Handle change in file extensions.""" | |
with zipf.open(pyoname) as gvp: | |
with open(tmppath, "wb") as gtfile: | |
gtfile.write(gvp.read()) | |
def generic_package_cracker(packname, pyoname, unpyc=False): | |
"""Open and decompile a mod package.""" | |
gpacks = get_mod_packages(packname) | |
if not gpacks: | |
return None | |
if len(gpacks) > 1: | |
raise SystemExit("MORE THAN ONE COPY OF {0} FOUND!".format(packname)) | |
else: | |
with tempfile.TemporaryDirectory() as tmpdirname: | |
tmppath = os.path.join(tmpdirname, "tempfile.pyc") | |
zipf = zipfile.ZipFile(gpacks[0]) | |
try: | |
zip_opener(zipf, pyoname, tmppath) | |
except KeyError: | |
pycname = pyoname.replace(".pyo", ".pyc") | |
zip_opener(zipf, pycname, tmppath) | |
with io.StringIO() as dummy: | |
decomp = decomp_function(tmppath, dummy, unpyc) | |
return decomp | |
def get_local_mccc(unpyc=False): | |
"""Get local MCCC version.""" | |
mcscript = "mc_cmd_center.ts4script" | |
mcpyo = "mc_cmd_version.pyo" | |
dtext = generic_package_cracker(mcscript, mcpyo, unpyc) | |
if dtext is None: | |
mcversion = "Not installed" | |
else: | |
mcbase = [txt for txt in dtext.split("\n") if "VERSION = " in txt][0] | |
mcversion = mcbase.split(" = '")[-1].replace("'", "") | |
return mcversion | |
def get_local_basemental(unpyc=False): | |
"""Get local Basemental Drugs version.""" | |
bmscript = "basementaldrugs.ts4script" | |
bmpyo = "bmdversion.pyo" | |
dtext = generic_package_cracker(bmscript, bmpyo, unpyc) | |
if dtext is None: | |
bmversion = "Not installed" | |
else: | |
bmbase = [txt for txt in dtext.split("\n") if "Current version" in txt][0] | |
bmraw = bmbase.split(": v")[-1] | |
if bmraw == bmbase: | |
bmversion = bmraw.split("Basemental Drugs ")[-1].replace("')", "") | |
else: | |
bmversion = bmraw.split("'")[0] | |
return bmversion | |
def get_local_wwhims(unpyc=False): | |
"""Get local Wicked Whims version.""" | |
wwscript = "TURBODRIVER_WickedWhims_Scripts.ts4script" | |
wwpyo = "wickedwhims/version_registry.pyo" | |
dtext = generic_package_cracker(wwscript, wwpyo, unpyc) | |
if dtext is None: | |
wwversion = "Not installed" | |
else: | |
dct = dtext.split("\n")[0:5] | |
wwbase = ".".join([field.split(" = ")[-1] for field in dct[0:4]]) | |
wwhotfix = string.ascii_lowercase[int(dct[4].split(" = ")[-1]) - 1] | |
wwversion = "{0}{1}".format(wwbase, wwhotfix) | |
return wwversion | |
def get_local_wperv(unpyc=False): | |
"""Get local Wicked Perversions version.""" | |
wpscript = "NisaK_Wicked_Perversions.ts4script" | |
wppyo = "NisaK/utilities/hazard_detector.pyo" | |
dtext = generic_package_cracker(wpscript, wppyo, unpyc) | |
if dtext is None: | |
wpversion = "Not installed" | |
else: | |
wpbase = [txt for txt in dtext.split("\n") if "NISA_MOD_VER" in txt][0] | |
wpalmost = wpbase.split(" = ")[-1].replace("'", "") | |
wpversion = ".".join(wpalmost.split(".")[1:]) | |
return wpversion | |
def get_local_game_version(): | |
"""Get local game version.""" | |
gvt = os.path.join(TS4FOLDER, "GameVersion.txt") | |
with open(gvt, "r") as afile: | |
gvtraw = afile.read() | |
gvtclean = gvtraw.split("\x00")[-1] | |
return gvtclean | |
def clean_latest_version(inver): | |
"""Extract latest game version from raw text.""" | |
inver2 = inver.split("-")[1].strip() | |
stripvers = [ver.strip() for ver in inver2.split("/")] | |
splitvers = [sver.split(" ") for sver in stripvers] | |
pcver = splitvers[0][1] | |
macver = splitvers[1][1] | |
return pcver, macver | |
def get_latest_versions(): | |
"""Scrape for latest game version.""" | |
req = requests.get(PATCHURL) | |
soup = bs4.BeautifulSoup(req.text, "html.parser") | |
h4s = soup.find_all("h4") | |
latest = h4s[0].text | |
pcver, macver = clean_latest_version(latest) | |
verdict = {"Windows": pcver, "Mac": macver} | |
return verdict | |
def get_platform_version(): | |
"""Get platform.""" | |
platsys = platform.system() | |
fplat = "Mac" if platsys == "Darwin" else "Windows" | |
return fplat | |
def get_latest_basemental(): | |
"""Scrape for latest Basemental Drugs version.""" | |
req = requests.get(BMDURL) | |
soup = bs4.BeautifulSoup(req.text, "html.parser") | |
alist = [atag for atag in soup.find_all("a") if "DOWNLOAD " in atag.text] | |
latest = alist[0].text.replace("DOWNLOAD BASEMENTAL DRUGS ", "").replace("!", "") | |
return latest | |
def get_latest_mccc(): | |
"""Scrape for latest MCCC version.""" | |
req = requests.get(MCURL) | |
soup = bs4.BeautifulSoup(req.text, "html.parser") | |
latesta = soup.find_all("a", string=re.compile("^MC Command Center"), attrs={"href": True})[0] | |
finalver = latesta.text.replace("MC Command Center ", "") | |
return finalver | |
def get_latest_wwhims(): | |
"""Scrape for latest Wicked Whims version.""" | |
req = requests.get(WWURL) | |
soup = bs4.BeautifulSoup(req.text, "html.parser") | |
attrdict = {"style": "text-align: center;"} | |
htwoes = soup.find_all("h2", attrs=attrdict, string=re.compile("^WickedWhims")) | |
latesth = htwoes[0].text | |
finalver = latesth.replace("WickedWhims ", "") | |
return finalver | |
def get_latest_wperv(): | |
"""Scrape for latest Wicked Perversions version.""" | |
req = requests.get(WPURL) | |
soup = bs4.BeautifulSoup(req.text, "html.parser") | |
latests = soup.find_all("section", {"data-controller": "downloads.front.view.changeLog"})[0] | |
finalver = latests.text.split("\n")[1].split("LL.")[-1] | |
return finalver | |
def current_versions(unpyc=False): | |
"""Pack local versions into a dict.""" | |
vcurrent = get_local_game_version() | |
mcurrent = get_local_mccc(unpyc) | |
bcurrent = get_local_basemental(unpyc) | |
wcurrent = get_local_wwhims(unpyc) | |
wpcurrent = get_local_wperv(unpyc) | |
curdict = {} | |
curdict["The Sims 4"] = vcurrent | |
curdict["MC Command Center"] = mcurrent | |
curdict["Basemental Drugs"] = bcurrent | |
curdict["Wicked Whims"] = wcurrent | |
curdict["Wicked Perversions"] = wpcurrent | |
return curdict | |
def latest_versions_remote(pg13): | |
"""Pack remote versions into a dict.""" | |
vlatest = get_latest_versions() | |
mlatest = get_latest_mccc() | |
if pg13: | |
blatest = None | |
wlatest = None | |
wplatest = None | |
else: | |
blatest = get_latest_basemental() | |
wlatest = get_latest_wwhims() | |
wplatest = get_latest_wperv() | |
platsys = get_platform_version() | |
latdict = {} | |
latdict["The Sims 4"] = vlatest[platsys] | |
latdict["MC Command Center"] = mlatest | |
latdict["Basemental Drugs"] = blatest | |
latdict["Wicked Whims"] = wlatest | |
latdict["Wicked Perversions"] = wplatest | |
return latdict | |
def main(llatest=False, unpyc=False, pg13=False): | |
"""Print latest versions with optional compare.""" | |
latdict = latest_versions_remote(pg13) | |
if llatest: | |
curdict = current_versions(unpyc) | |
print("LATEST PUBLIC VERSIONS") | |
print("~"*32) | |
for key, val in latdict.items(): | |
print("{0}: {1}".format(key, val)) | |
if llatest: | |
print("\tYour version: {0}".format(curdict[key])) | |
def handle_args(): | |
"""Take arguments from command line.""" | |
parser = argparse.ArgumentParser(epilog=GISTURL) | |
parser.add_argument("-u", | |
"--update-check", | |
dest="llatest", | |
help="check if local game/mods are up to date", | |
action="store_true", | |
default=False) | |
parser.add_argument("--pg13", | |
dest="pg13", | |
help="don't check adult mods for updates", | |
action="store_true", | |
default=False) | |
if UNPYC: | |
parser.add_argument("--unpyc3", | |
dest="unpyc3", | |
help="use unpyc3 instead of uncompyle6", | |
action="store_true", | |
default=False) | |
parser.set_defaults() | |
args = parser.parse_args(sys.argv[1:]) | |
if not UNPYC: | |
args.unpyc3 = False | |
main(args.llatest, args.unpyc3, args.pg13) | |
if __name__ == "__main__": | |
handle_args() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment