#!/usr/bin/env python3
import argparse
import os
import sys
import shutil
import requests
import pathlib
import hashlib
import util
from util import config
# Apply updates to the actual mod pack
def install():
mods_location = os.path.join(config["pack"]["location"], "mods")
whitelist = config["pack"]["whitelist"]
version_file = "version.txt"
pack_version = util.get_version_from_file(version_file)
print("Updating pack with version " + str(pack_version) + "...")
print()
# create the mods folder if it doesn't already exist
pathlib.Path(mods_location).mkdir(parents=True, exist_ok=True)
# (fname, checksum, url)
mods = util.read_file(version_file)
names = [mod[0] for mod in mods]
# whitelist client mods (e.g. optifine)
names += whitelist
i = 0
for mod in mods:
mod_path = os.path.join(mods_location, mod[0])
i += 1
if os.path.exists(mod_path) and os.path.isfile(mod_path) and \
hashlib.sha1(open(mod_path, 'rb').read()).hexdigest() == mod[1]:
print("Skipping {mod[0]}, already up to date".format(mod=mod))
else:
print('Installing {mod[0]} from {mod[2]}...'.format(mod=mod))
print(' ({i} of {x})'.format(i=i,x=len(mods)), end='\r')
download_obj = requests.get(mod[2], stream=True)
with open(mod_path, "wb") as write_file:
shutil.copyfileobj(download_obj.raw, write_file)
print("Done!" + " " * 8)
print()
print("Removing old mods...")
for jar in os.listdir(mods_location):
if jar not in names and os.path.splitext(jar)[1] == ".jar":
os.remove(os.path.join(mods_location, jar))
print("Removing '{jar}'".format(jar=jar))
print()
print("Finished installing mods!")
# Using the latest urls, update downloads.txt to match and have the correct sha1
def apply_updates(mods, version_file, game_version=(2, 0, 0)):
pack_version = util.get_version_from_file(version_file)
print("Populating version file...")
print("Getting new versions of all mods...")
mod_urls = util.find_updated_urls([x for x in mods.values()], game_version, threads=3)
print("Downloading and checksumming all mods...")
checksums = util.find_checksums(mod_urls)
# Write information out to version.txt
with open(version_file, 'w') as f:
f.write('# Format: <jarname> <hex digested sha1> <direct download url>\n')
f.write("#VERSION " + str(pack_version + 1) + "\n")
for name, checksum, url in zip((k+'.jar' for k in mods.keys()), checksums, mod_urls):
f.write(f'{name} {checksum} {url}\n')
print()
print("Done!")
print(f"Updates applied to {version_file}")
print("New pack version is " + str(pack_version + 1))
print("[!] No mods were installed. To update your mods folder, run 'update.py install'")
# Find if any updates are available
def check_updates(mods, version_file, version=(2, 0, 0)):
pack_version = util.get_version_from_file(version_file)
print("Checking for updates to version " + str(pack_version) + "...")
latest = [(k, mods[k]) for k in mods.keys()]
old = util.read_file(version_file)
old_urls = [mod[2] for mod in old]
num_updates = 0
print("Checking updates...")
ffx = util.firefox()
for mod in latest:
print("Checking for updates to {mod[0]}...".format(mod=mod), end="")
sys.stdout.flush() # takes care of line-buffered terminals
if 'curseforge' in mod[1]:
url = util.find_cdn(ffx, mod[1], version)
else:
url = requests.get(mod[1]).url
if url in old_urls:
print(" No updates")
else:
print(" Found update: " + url.split('/')[-1])
num_updates += 1
ffx.close()
print("Finished checking for updates. {num} mods can be updated".format(num=num_updates))
if num_updates >= 0:
print("Run 'python update.py apply_updates' to create a new version with these updates applied.")
parser = argparse.ArgumentParser(
description="A Simple Git-Based Modpack Manager",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''\
Available commands:
install : Downloads mods listed in version.txt and populates the mods folder specified in pack-location.txt
apply_updates : Using the urls in mods.txt, repopulates version.txt to reflect the most recent mod versions
check_updates : Compares version.txt and mods.txt to see if any mods can be updated
''')
parser.add_argument('command',
nargs='?',
default='install',
help="The action to perform (default: install)")
if __name__ == "__main__":
args = parser.parse_args()
mods = config['mods']
pack = config['pack']
# run the command
if args.command == "install":
install("version.txt", config['pack']["whitelist"], os.path.join(config['pack']['location'], 'mods'))
elif args.command == "apply_updates":
apply_updates(config['mods'], "version.txt", config['pack']["game_version"])
elif args.command == "check_updates":
check_updates(config['mods'], "version.txt", config['pack']["game_version"])
else:
print("Error: command \"" + args.command + "\" does not exist")
parser.print_help()
sys.exit(1)