ModpackUpdater/Backend.py

289 lines
10 KiB
Python

import io
import json
import tempfile
import subprocess
import time
import os
import datetime
import zipfile
import tarfile
from pathlib import Path
import shutil
from FTP import *
def install_prism():
global data_dir
if not os.path.exists(os.path.join(data_dir, "prism")):
install_java(21)
suff = "win.zip"
if os.name == "posix":
suff = "lin.tar.gz"
prism_file = "prism/prism-"+suff
with io.BytesIO() as buff:
ftpDownload(prism_file, buff)
buff.seek(0)
if os.name == "nt":
with zipfile.ZipFile(buff) as zip:
zip.extractall(os.path.join(data_dir, "prism"))
else:
with tarfile.open(fileobj=buff) as tar:
tar.extractall(os.path.join(data_dir, "prism"))
with io.BytesIO() as buff:
ftpDownload("prism/prismlauncher.cfg", buff)
buff.seek(0)
with open(os.path.join(data_dir, "prism", "prismlauncher.cfg"), 'wb') as file:
file.write(buff.getbuffer())
suff = "win"
cmd = "java.exe"
if os.name == "posix":
suff = "lin"
cmd = "java"
data = []
with open(os.path.join(data_dir, "prism", "prismlauncher.cfg"), 'r') as file:
data = file.readlines()
for ind, line in enumerate(data):
if line.startswith("JavaPath="):
data[ind] = "JavaPath="+data_dir.replace("\\", "/")+"/java/java-21-"+suff+"/bin/"+cmd+"\n"
with open(os.path.join(data_dir, "prism", "prismlauncher.cfg"), 'w') as file:
file.writelines(data)
def get_tar_members_stripped(tar, n_folders_stripped = 1):
members = []
for member in tar.getmembers():
p = Path(member.path)
member.path = p.relative_to(*p.parts[:n_folders_stripped])
members.append(member)
return members
def unzip(zip, dest):
for file_info in zip.infolist():
if file_info.is_dir():
continue
file_path = file_info.filename
extracted_path = file_path.split("/", 1)[1]
extracted_path = os.path.join(dest, extracted_path)
print(extracted_path)
os.makedirs(os.path.dirname(extracted_path), exist_ok=True)
with open(extracted_path, 'wb') as dst:
with zip.open(file_info, 'r') as src:
shutil.copyfileobj(src, dst)
def get_java_version(mc_version):
global data_dir
tokens = mc_version.split(".")
java = 8
if tokens[1] == "17":
java = 17
elif tokens[1] == "18" or tokens[1] == "19":
java = 17
elif int(tokens[1]) > 19:
if tokens[1] == "20" and int(tokens[2]) < 5:
java = 17
else:
java = 21
return java
def install_java(java):
suff = "win"
ext = ".zip"
if os.name == "posix":
suff = "lin"
ext = ".tar.gz"
java_path = "java/java-"+str(java)+"-"+suff+ext
if not os.path.exists(data_dir+"/java/java-"+str(java)+"-"+suff):
print("Downloading Java "+str(java))
with io.BytesIO() as buff:
ftpDownload(java_path, buff)
if os.name == "posix":
buff.seek(0)
with tarfile.open(fileobj=buff) as tar:
print(tar.getnames())
tar.extractall(data_dir+"/java/java-"+str(java)+"-"+suff, members=get_tar_members_stripped(tar, 1))
else:
with zipfile.ZipFile(buff) as zip:
unzip(zip, data_dir+"/java/java-"+str(java)+"-"+suff)
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):
global data_dir
if os.name == "posix":
data_dir = os.getenv("HOME") + "/.local/share/FCLauncher"
else:
data_dir = os.getenv("APPDATA") + "/FCLauncher"
Path(data_dir).mkdir(parents=True, exist_ok=True)
Path(data_dir+"/java").mkdir(parents=True, exist_ok=True)
install_prism()
if os.name == "nt":
prism_command = os.path.join(data_dir, "prism", "prismlauncher.exe")
else:
prism_command = os.path.join(data_dir, "prism", "PrismLauncher")
prism_instance_path = os.path.join(data_dir, "prism", "instances")
try:
# Fetching versions.json from FTP
bio = io.BytesIO()
ftpDownload(pack+"/versions.json", bio)
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(pack+"/"+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"]:
info_file_path = os.path.join(prism_instance_path, instance_name, "mmc-pack.json")
mc_version = ""
with open(info_file_path) as file:
info = json.load(file)
for component in info["components"]:
if component["uid"] == "net.minecraft":
mc_version = component["version"]
break;
java = get_java_version(mc_version)
install_java(java)
option_path = os.path.join(prism_instance_path, instance_name, "instance.cfg")
data = []
suff = "win"
cmd = "java.exe"
if os.name == "posix":
suff = "lin"
cmd = "java"
with open(option_path, 'r') as file:
data = file.readlines()
was_set = False
for ind, line in enumerate(data):
if line.startswith("JavaPath="):
data[ind] = "JavaPath="+data_dir.replace("\\", "/")+"/java/java-"+str(java)+"-"+suff+"/bin/"+cmd+"\n"
was_set = True
if not was_set:
data.append("JavaPath="+data_dir.replace("\\", "/")+"/java/java-"+str(java)+"-"+suff+"/bin/"+cmd+"\n")
data.append("OverrideJavaLocation=true\n")
data.append("OverrideJava=true\n")
with open(option_path, 'w') as file:
file.writelines(data)
print(data)
subprocess.run([prism_command, '-l', instance_name])
time.sleep(30)
break
else:
subprocess.run([prism_command, '-l', instance_name])
except Exception as e:
print(e)
print("Unable to check for updates. Modpack may be out of date")
subprocess.run([prism_command, '-l', instance_name])
def upload_pack(username, password, version_tag, fileName, pack):
bio = io.BytesIO()
ftpDownload(pack+"/versions.json", bio)
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()
ftpUpload(pack+"/"+versions[-1]["File"], zipbytes, username, password)
bio = io.BytesIO()
bio.write(json.dumps(versions).encode())
ftpUpload(pack+"/versions.json", bio, username, password)
bio.close()
modpackUpdate(pack, username, password)
def getModpacks():
bio = io.BytesIO()
ftpDownload("modpacks.json", bio)
bio.seek(0)
return json.load(bio)
def uploadModpacks(modpacks, username, password):
bio = io.BytesIO()
bio.write(json.dumps(modpacks).encode())
ftpUpload("modpacks.json", bio, username, password)
bio.close()
def modpackUpdate(id, username, password):
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, username, password);
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})
uploadModpacks(modpacks, username, password)
ftpMakeDirectory(id, username, password)
versions = []
bio = io.BytesIO()
bio.write(json.dumps(versions).encode())
ftpUpload(id+"/versions.json", bio, username, password)
ftpMakeDirectory(id+"/Versions", username, password)
def deleteModpack(username, password, id):
modpacks = getModpacks()
for pack in modpacks:
if pack["id"] == id:
modpacks.remove(pack)
break
uploadModpacks(modpacks, username, password)
ftpDeleteDirectory(id, username, password)