aboutsummaryrefslogblamecommitdiff
path: root/modpackman.py
blob: 1bd28d4f5139027f57e261e2fd671a71900f7c01 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                      


               

           


                                      



                                                                    


























































































                                                                                                         















                                                                                                                        
 

                              


                         

                                 
                                                                                                             
                                         
                                                                                    
                                         
                                                                                    



                                                                       
#!/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)