from ftplib import FTP_TLS as FTP import io import json import tempfile import subprocess import time import os import datetime import zipfile from customtkinter import * import time import math def resource_path(relative_path): try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) def perform_installation(instance_name, prism_command, prism_instance_path, pack): try: ftp = FTP("gitea.piwalker.net") ftp.login() ftp.prot_p() ftp.cwd(pack) # Fetching versions.json from FTP bio = io.BytesIO() ftp.retrbinary("RETR versions.json", bio.write) bio.seek(0) versions = json.load(bio) bio.close() # Checking current version version = "0.0.0" version_file_path = os.path.join(prism_instance_path, instance_name, ".minecraft", "version.txt") if os.path.exists(version_file_path): with open(version_file_path, 'r') as fp: version = fp.readline().rstrip() # Checking if update is needed if version != versions[-1]["Version"]: print(f"Current version: {version}") print(f"Latest version: {versions[-1]['Version']}") # Downloading modpack with tempfile.TemporaryDirectory() as temp_dir: modpack_file_path = os.path.join(temp_dir, instance_name + ".mrpack") with open(modpack_file_path, 'wb') as modpack: ftpDownload(ftp, versions[-1]["File"], modpack) # Running PrismLauncher with modpack subprocess.Popen([prism_command, '-I', modpack_file_path]) # Waiting for installation to complete while True: time.sleep(5) if os.path.exists(version_file_path): with open(version_file_path, 'r') as fp: version = fp.readline().rstrip() if version == versions[-1]["Version"]: break except Exception as e: print(e) print("Unable to check for updates. Modpack may be out of date") finally: # Launching PrismLauncher with the instance subprocess.run([prism_command, '-l', instance_name]) def upload_pack(username, password, version_tag, fileName, pack): ftp = FTP("gitea.piwalker.net", username, password) ftp.prot_p() ftp.cwd(pack) bio = io.BytesIO() ftp.retrbinary("RETR versions.json", bio.write) bio.seek(0) versions = json.load(bio) bio.close() time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") versions.append({"Version":version_tag, "Date":time, "File":"Versions/"+pack+time+".mrpack"}) with zipfile.ZipFile(fileName, 'r') as zin: zipbytes = io.BytesIO() zout = zipfile.ZipFile(zipbytes, 'w') for item in zin.infolist(): buffer = zin.read(item.filename) if item.filename != "overrides/version.txt": zout.writestr(item, buffer) zout.writestr("overrides/version.txt", version_tag) zout.close() zipbytes.seek(0) ftp.storbinary("STOR "+versions[len(versions)-1]["File"], zipbytes) bio = io.BytesIO() bio.write(json.dumps(versions).encode()) bio.seek(0) ftp.storbinary("STOR versions.json", bio) bio.close() modpackUpdate(pack, ftp) ftp.close() def getModpacks(): ftp = FTP("gitea.piwalker.net") ftp.login() ftp.prot_p() bio = io.BytesIO() ftp.retrbinary("RETR modpacks.json", bio.write) bio.seek(0) ftp.close() return json.load(bio) def uploadModpacks(modpacks, ftp): ftp.cwd("/ftp"); bio = io.BytesIO() bio.write(json.dumps(modpacks).encode()) bio.seek(0) ftp.storbinary("STOR modpacks.json", bio) bio.close() def modpackUpdate(id, ftp): modpacks = getModpacks() time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") for modpack in modpacks: if modpack["id"] == id: modpack["last-updated"] = time uploadModpacks(modpacks, ftp); def createModpack(id, name, username, password): modpacks = getModpacks() time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") modpacks.append({"id":id, "name":name, "last-updated":time}) ftp = FTP("gitea.piwalker.net", username, password) ftp.prot_p() uploadModpacks(modpacks,ftp) ftp.mkd(id) ftp.cwd(id) versions = [] bio = io.BytesIO() bio.write(json.dumps(versions).encode()) bio.seek(0) ftp.storbinary("STOR versions.json", bio) ftp.mkd("Versions") ftp.close() def deleteModpack(username, password, id): ftp = FTP("gitea.piwalker.net", username, password) ftp.prot_p() modpacks = getModpacks() for pack in modpacks: if pack["id"] == id: modpacks.remove(pack) break uploadModpacks(modpacks, ftp) deleteFolder(ftp, id) def deleteFolder(ftp, path): print("Deleting folder: "+path) ftp.cwd(path) for item in ftp.nlst(): try: print("deleting file: "+path) ftp.delete(item) except: deleteFolder(ftp, item) ftp.cwd("..") ftp.rmd(path) def ftpDownload(ftp, file, stream): #create tkinter window print("downloading file: "+file) dialog = CTk() if os.name == 'posix': dialog.attributes('-type', 'dialog') dialog.title("Downloading Modpack") set_appearance_mode("dark") set_default_color_theme("blue") global pbar pbar = CTkProgressBar(master=dialog) pbar.pack(padx=20, pady=20) global progress global ETA progress = StringVar() ETA = StringVar() progress_label = CTkLabel(master=dialog, textvariable=progress) progress_label.pack() eta_label = CTkLabel(master=dialog, textvariable=ETA) eta_label.pack() size = ftp.size(file) global total total = 0 global start global timer timer = 0 start = time.time() dialog.update() def downloadCallback(data): global total global pbar global start global progress global ETA global timer stream.write(data) total += len(data) if time.time() - timer >= 1: progress.set(str(round(total/1048576, 1))+" MB / "+str(round(size/1048576, 1))+" MB @ " + str(round((total/1048576)/(time.time()-start), 3))+" MB/s") time_left = (size-total)/(total/(time.time()-start)) ETA.set("ETA: " + str(datetime.timedelta(seconds=math.ceil(time_left)))) pbar.set(total/size) timer = time.time() dialog.update() ftp.retrbinary("RETR " + file, downloadCallback) dialog.destroy()