ModpackUpdater/Backend.py

294 lines
11 KiB
Python
Raw Permalink Normal View History

2024-06-20 08:30:57 -06:00
import io
import json
import tempfile
import subprocess
import time
import os
import datetime
import zipfile
2024-06-20 21:24:17 -06:00
import tarfile
from pathlib import Path
2024-06-20 22:26:30 -06:00
import shutil
2024-06-21 14:39:44 -06:00
from FTP import *
2024-06-21 16:23:39 -06:00
import socket
2024-06-20 21:24:17 -06:00
2024-06-21 09:07:38 -06:00
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:
2024-06-21 14:39:44 -06:00
ftpDownload(prism_file, buff)
2024-06-21 09:07:38 -06:00
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:
2024-06-21 14:39:44 -06:00
ftpDownload("prism/prismlauncher.cfg", buff)
2024-06-21 09:07:38 -06:00
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"
2024-06-21 16:23:39 -06:00
if line.startswith("LastHostname="):
data[ind] = "LastHostname="+socket.gethostname()+"\n"
2024-06-21 09:07:38 -06:00
with open(os.path.join(data_dir, "prism", "prismlauncher.cfg"), 'w') as file:
file.writelines(data)
2024-06-20 21:24:17 -06:00
2024-06-21 16:23:39 -06:00
2024-06-20 21:24:17 -06:00
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
2024-06-20 22:26:30 -06:00
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)
2024-06-21 09:07:38 -06:00
def get_java_version(mc_version):
2024-06-20 21:24:17 -06:00
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
2024-06-21 09:07:38 -06:00
return java
2024-06-20 21:24:17 -06:00
2024-06-21 09:07:38 -06:00
def install_java(java):
2024-06-20 21:24:17 -06:00
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:
2024-06-21 14:39:44 -06:00
ftpDownload(java_path, buff)
2024-06-20 21:24:17 -06:00
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))
2024-06-20 22:26:30 -06:00
else:
with zipfile.ZipFile(buff) as zip:
unzip(zip, data_dir+"/java/java-"+str(java)+"-"+suff)
2024-06-20 21:24:17 -06:00
2024-06-20 16:09:18 -06:00
2024-06-20 08:30:57 -06:00
2024-06-20 17:47:35 -06:00
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)
2024-06-20 08:30:57 -06:00
def perform_installation(instance_name, prism_command, prism_instance_path, pack):
2024-06-20 21:24:17 -06:00
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)
2024-06-21 09:07:38 -06:00
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")
2024-06-20 21:24:17 -06:00
try:
2024-06-20 08:30:57 -06:00
# Fetching versions.json from FTP
bio = io.BytesIO()
2024-06-21 14:39:44 -06:00
ftpDownload(pack+"/versions.json", bio)
bio.seek(0)
versions = json.load(bio)
bio.close()
2024-06-20 08:30:57 -06:00
# 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()
2024-06-20 08:30:57 -06:00
# Checking if update is needed
if version != versions[-1]["Version"]:
print(f"Current version: {version}")
print(f"Latest version: {versions[-1]['Version']}")
2024-06-20 08:30:57 -06:00
# 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:
2024-06-21 14:39:44 -06:00
ftpDownload(pack+"/"+versions[-1]["File"], modpack)
# Running PrismLauncher with modpack
subprocess.Popen([prism_command, '-I', modpack_file_path])
2024-06-20 08:30:57 -06:00
# 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"]:
2024-06-20 21:24:17 -06:00
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;
2024-06-21 09:07:38 -06:00
java = get_java_version(mc_version)
install_java(java)
2024-06-20 21:24:17 -06:00
option_path = os.path.join(prism_instance_path, instance_name, "instance.cfg")
data = []
suff = "win"
2024-06-20 22:26:30 -06:00
cmd = "java.exe"
2024-06-20 21:24:17 -06:00
if os.name == "posix":
suff = "lin"
2024-06-20 22:26:30 -06:00
cmd = "java"
2024-06-20 21:24:17 -06:00
with open(option_path, 'r') as file:
data = file.readlines()
was_set = False
for ind, line in enumerate(data):
if line.startswith("JavaPath="):
2024-06-20 22:26:30 -06:00
data[ind] = "JavaPath="+data_dir.replace("\\", "/")+"/java/java-"+str(java)+"-"+suff+"/bin/"+cmd+"\n"
2024-06-20 21:24:17 -06:00
was_set = True
if not was_set:
2024-06-20 22:26:30 -06:00
data.append("JavaPath="+data_dir.replace("\\", "/")+"/java/java-"+str(java)+"-"+suff+"/bin/"+cmd+"\n")
2024-06-20 21:24:17 -06:00
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
2024-06-20 21:24:17 -06:00
else:
subprocess.run([prism_command, '-l', instance_name])
2024-06-20 16:09:18 -06:00
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])
2024-06-20 08:30:57 -06:00
def upload_pack(username, password, version_tag, fileName, pack):
2024-06-20 08:30:57 -06:00
bio = io.BytesIO()
2024-06-21 14:39:44 -06:00
ftpDownload(pack+"/versions.json", bio)
2024-06-20 08:30:57 -06:00
bio.seek(0)
versions = json.load(bio)
bio.close()
time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
2024-06-21 14:39:44 -06:00
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()
2024-06-21 14:39:44 -06:00
ftpUpload(pack+"/"+versions[-1]["File"], zipbytes, username, password)
2024-06-20 08:30:57 -06:00
bio = io.BytesIO()
bio.write(json.dumps(versions).encode())
2024-06-21 14:39:44 -06:00
ftpUpload(pack+"/versions.json", bio, username, password)
2024-06-20 08:30:57 -06:00
bio.close()
2024-06-21 14:39:44 -06:00
modpackUpdate(pack, username, password)
2024-06-20 08:30:57 -06:00
def getModpacks():
bio = io.BytesIO()
2024-06-21 14:39:44 -06:00
ftpDownload("modpacks.json", bio)
bio.seek(0)
return json.load(bio)
2024-06-21 14:39:44 -06:00
def uploadModpacks(modpacks, username, password):
bio = io.BytesIO()
bio.write(json.dumps(modpacks).encode())
2024-06-21 14:39:44 -06:00
ftpUpload("modpacks.json", bio, username, password)
bio.close()
2024-06-21 14:39:44 -06:00
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
2024-06-21 14:39:44 -06:00
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})
2024-06-21 14:39:44 -06:00
uploadModpacks(modpacks, username, password)
ftpMakeDirectory(id, username, password)
versions = []
bio = io.BytesIO()
bio.write(json.dumps(versions).encode())
2024-06-21 14:39:44 -06:00
ftpUpload(id+"/versions.json", bio, username, password)
ftpMakeDirectory(id+"/Versions", username, password)
2024-06-20 16:09:18 -06:00
def deleteModpack(username, password, id):
modpacks = getModpacks()
for pack in modpacks:
if pack["id"] == id:
modpacks.remove(pack)
break
2024-06-21 14:39:44 -06:00
uploadModpacks(modpacks, username, password)
ftpDeleteDirectory(id, username, password)