mirror of
https://github.com/Radiquum/YAMPD.git
synced 2025-05-20 07:39:35 +05:00
Merge pull request 'Refactor functions to a shared module' (#1) from Decouple_from_Flask into main
Reviewed-on: #1
This commit is contained in:
commit
c78314fb0a
13 changed files with 479 additions and 222 deletions
|
@ -52,8 +52,10 @@ export default function PackPage() {
|
||||||
const res = await fetch(PACK_ENDPOINT("getPack", id));
|
const res = await fetch(PACK_ENDPOINT("getPack", id));
|
||||||
if (!res.ok) router.push("/404");
|
if (!res.ok) router.push("/404");
|
||||||
const data: Pack = await res.json();
|
const data: Pack = await res.json();
|
||||||
setPackData(data);
|
if (data._id) {
|
||||||
setPackDataLoading(false);
|
setPackData(data);
|
||||||
|
setPackDataLoading(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -3,3 +3,4 @@ flaskwebgui
|
||||||
requests
|
requests
|
||||||
Pillow
|
Pillow
|
||||||
flask-socketio
|
flask-socketio
|
||||||
|
tqdm
|
|
@ -1,63 +1,15 @@
|
||||||
import os
|
import os
|
||||||
from . import apiDownload
|
from . import apiDownload
|
||||||
from flask import request, jsonify, send_file, redirect, url_for, abort
|
from flask import request, jsonify
|
||||||
from config import PACKS_FOLDER
|
from config import PACKS_FOLDER
|
||||||
import json
|
import json
|
||||||
from flask_socketio import emit
|
from flask_socketio import emit
|
||||||
import requests
|
|
||||||
|
|
||||||
|
from shared.download import download
|
||||||
def download(path, url, name, total):
|
|
||||||
r = requests.get(url, stream=True)
|
|
||||||
if r.status_code != 200:
|
|
||||||
emit(
|
|
||||||
"download_current",
|
|
||||||
{
|
|
||||||
"status": "error",
|
|
||||||
"message": f"Got a HTTP ERROR {r.status_code} while downloading {name}",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"status": "error",
|
|
||||||
"message": f"Got a HTTP ERROR {r.status_code} while downloading {name}",
|
|
||||||
}
|
|
||||||
downloaded = 0
|
|
||||||
if os.path.exists(f"{path}/{name}"):
|
|
||||||
emit(
|
|
||||||
"download_current",
|
|
||||||
{"status": "ok", "message": f"{name} already downloaded"},
|
|
||||||
namespace="/",
|
|
||||||
broadcast=True,
|
|
||||||
)
|
|
||||||
return {"status": "ok", "message": f"{name} already downloaded"}
|
|
||||||
with open(f"{path}/{name}", "wb") as fp:
|
|
||||||
for data in r.iter_content(chunk_size=1024):
|
|
||||||
size = fp.write(data)
|
|
||||||
downloaded += size
|
|
||||||
emit(
|
|
||||||
"download_current",
|
|
||||||
{
|
|
||||||
"status": "pending",
|
|
||||||
"total_bytes": total,
|
|
||||||
"download_bytes": downloaded,
|
|
||||||
},
|
|
||||||
namespace="/",
|
|
||||||
broadcast=True,
|
|
||||||
)
|
|
||||||
emit(
|
|
||||||
"download_current",
|
|
||||||
{"status": "ok", "message": f"{name} downloaded"},
|
|
||||||
namespace="/",
|
|
||||||
broadcast=True,
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"status": "ok",
|
|
||||||
"message": f"{name} downloaded",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@apiDownload.route("/pack", methods=["POST"])
|
@apiDownload.route("/pack", methods=["POST"])
|
||||||
def downloadPack():
|
def downloadPackEndpoint():
|
||||||
pack = {}
|
pack = {}
|
||||||
pack_id = request.json.get("pack_id")
|
pack_id = request.json.get("pack_id")
|
||||||
|
|
||||||
|
@ -66,11 +18,33 @@ def downloadPack():
|
||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
mods = pack.get("mods", [])
|
mods = pack.get("mods", [])
|
||||||
total = len(mods)
|
queue = []
|
||||||
|
for mod in mods:
|
||||||
|
queue.append(
|
||||||
|
{
|
||||||
|
"slug": mod.get("slug"),
|
||||||
|
"title": mod.get("file").get("title"),
|
||||||
|
"url": mod.get("file").get("url"),
|
||||||
|
"filename": mod.get("file").get("filename"),
|
||||||
|
"size": mod.get("file").get("size"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
for dep in mod.get("dependencies"):
|
||||||
|
queue.append(
|
||||||
|
{
|
||||||
|
"slug": dep.get("slug"),
|
||||||
|
"title": dep.get("file").get("title"),
|
||||||
|
"url": dep.get("file").get("url"),
|
||||||
|
"filename": dep.get("file").get("filename"),
|
||||||
|
"size": dep.get("file").get("size"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
queue = list({mod["slug"]: mod for mod in queue}.values())
|
||||||
|
total = len(queue)
|
||||||
|
|
||||||
os.makedirs(f"{PACKS_FOLDER}/{pack_id}/mods", exist_ok=True)
|
os.makedirs(f"{PACKS_FOLDER}/{pack_id}/mods", exist_ok=True)
|
||||||
|
|
||||||
for i, mod in enumerate(mods):
|
for i, mod in enumerate(queue):
|
||||||
emit(
|
emit(
|
||||||
"download_total",
|
"download_total",
|
||||||
{
|
{
|
||||||
|
@ -78,17 +52,37 @@ def downloadPack():
|
||||||
"total": total,
|
"total": total,
|
||||||
"current": i,
|
"current": i,
|
||||||
"title": mod.get("title"),
|
"title": mod.get("title"),
|
||||||
"filename": mod.get("file").get("filename"),
|
"filename": mod.get("filename"),
|
||||||
},
|
},
|
||||||
namespace="/",
|
namespace="/",
|
||||||
broadcast=True,
|
broadcast=True,
|
||||||
)
|
)
|
||||||
download(
|
status, message = download(
|
||||||
f"{PACKS_FOLDER}/{pack_id}/mods",
|
f"{PACKS_FOLDER}/{pack_id}/mods",
|
||||||
mod.get("file").get("url"),
|
mod.get("url"),
|
||||||
mod.get("file").get("filename"),
|
mod.get("filename"),
|
||||||
mod.get("file").get("size"),
|
mod.get("size"),
|
||||||
)
|
)
|
||||||
|
if status is False:
|
||||||
|
emit(
|
||||||
|
"download_current",
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": message,
|
||||||
|
},
|
||||||
|
namespace="/",
|
||||||
|
broadcast=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
emit(
|
||||||
|
"download_current",
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"message": mod.get("filename"),
|
||||||
|
},
|
||||||
|
namespace="/",
|
||||||
|
broadcast=True,
|
||||||
|
)
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
"download_total",
|
"download_total",
|
||||||
|
@ -111,7 +105,7 @@ def downloadPack():
|
||||||
|
|
||||||
|
|
||||||
@apiDownload.route("/mods", methods=["POST"])
|
@apiDownload.route("/mods", methods=["POST"])
|
||||||
def downloadMods():
|
def downloadModsEndpoint():
|
||||||
pack = {}
|
pack = {}
|
||||||
pack_id = request.json.get("pack_id")
|
pack_id = request.json.get("pack_id")
|
||||||
mods_slugs = request.json.get("mods")
|
mods_slugs = request.json.get("mods")
|
||||||
|
@ -121,31 +115,73 @@ def downloadMods():
|
||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
mods = pack.get("mods", [])
|
mods = pack.get("mods", [])
|
||||||
total = len(mods_slugs)
|
queue = []
|
||||||
|
for slug in mods_slugs:
|
||||||
|
for mod in mods:
|
||||||
|
if mod.get("slug") == slug:
|
||||||
|
queue.append(
|
||||||
|
{
|
||||||
|
"slug": mod.get("slug"),
|
||||||
|
"title": mod.get("file").get("title"),
|
||||||
|
"url": mod.get("file").get("url"),
|
||||||
|
"filename": mod.get("file").get("filename"),
|
||||||
|
"size": mod.get("file").get("size"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
for dep in mod.get("dependencies"):
|
||||||
|
queue.append(
|
||||||
|
{
|
||||||
|
"slug": dep.get("slug"),
|
||||||
|
"title": dep.get("file").get("title"),
|
||||||
|
"url": dep.get("file").get("url"),
|
||||||
|
"filename": dep.get("file").get("filename"),
|
||||||
|
"size": dep.get("file").get("size"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
queue = list({mod["slug"]: mod for mod in queue}.values())
|
||||||
|
total = len(queue)
|
||||||
|
|
||||||
os.makedirs(f"{PACKS_FOLDER}/{pack_id}/mods", exist_ok=True)
|
os.makedirs(f"{PACKS_FOLDER}/{pack_id}/mods", exist_ok=True)
|
||||||
|
|
||||||
for i, slug in enumerate(mods_slugs):
|
for i, mod in enumerate(queue):
|
||||||
for mod in mods:
|
emit(
|
||||||
if mod.get("slug") == slug:
|
"download_total",
|
||||||
emit(
|
{
|
||||||
"download_total",
|
"status": "ok",
|
||||||
{
|
"total": total,
|
||||||
"status": "ok",
|
"current": i,
|
||||||
"total": total,
|
"title": mod.get("title"),
|
||||||
"current": i,
|
"filename": mod.get("filename"),
|
||||||
"title": mod.get("title"),
|
},
|
||||||
"filename": mod.get("file").get("filename"),
|
namespace="/",
|
||||||
},
|
broadcast=True,
|
||||||
namespace="/",
|
)
|
||||||
broadcast=True,
|
status, message = download(
|
||||||
)
|
f"{PACKS_FOLDER}/{pack_id}/mods",
|
||||||
download(
|
mod.get("url"),
|
||||||
f"{PACKS_FOLDER}/{pack_id}/mods",
|
mod.get("filename"),
|
||||||
mod.get("file").get("url"),
|
mod.get("size"),
|
||||||
mod.get("file").get("filename"),
|
)
|
||||||
mod.get("file").get("size"),
|
if status is False:
|
||||||
)
|
emit(
|
||||||
|
"download_current",
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": message,
|
||||||
|
},
|
||||||
|
namespace="/",
|
||||||
|
broadcast=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
emit(
|
||||||
|
"download_current",
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"message": mod.get("filename"),
|
||||||
|
},
|
||||||
|
namespace="/",
|
||||||
|
broadcast=True,
|
||||||
|
)
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
"download_total",
|
"download_total",
|
||||||
|
@ -162,6 +198,6 @@ def downloadMods():
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"message": f"download of {pack_id} with {total} mods finished",
|
"message": f"download of {total} mods finished",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
135
src/api/pack.py
135
src/api/pack.py
|
@ -1,26 +1,19 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from . import apiPack
|
from . import apiPack
|
||||||
from flask import request, jsonify, send_file, redirect, url_for, abort
|
from flask import request, jsonify, send_file, redirect, url_for
|
||||||
from config import PACKS_FOLDER, IMG_ALLOWED_MIME
|
from config import PACKS_FOLDER, IMG_ALLOWED_MIME
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import base64
|
import base64
|
||||||
import json
|
from shared.pack import getPack, addMod, deleteMod
|
||||||
from .source import Modrinth, CurseForge
|
|
||||||
|
|
||||||
|
|
||||||
@apiPack.route("/<id>", methods=["GET"])
|
@apiPack.route("/<id>", methods=["GET"])
|
||||||
def getPack(id):
|
def getPackEndpoint(id):
|
||||||
if not os.path.exists(f"{PACKS_FOLDER}/{id}/packfile.json"):
|
pack = getPack(id)
|
||||||
|
if pack is None:
|
||||||
return jsonify({"status": "error", "message": "pack not found"}), 404
|
return jsonify({"status": "error", "message": "pack not found"}), 404
|
||||||
|
|
||||||
pack = {}
|
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
|
||||||
pack = json.load(fp)
|
|
||||||
pack["_id"] = id
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return jsonify(pack)
|
return jsonify(pack)
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,73 +56,35 @@ def editPackImage(id):
|
||||||
|
|
||||||
|
|
||||||
@apiPack.route("/<id>/mod/add", methods=["POST"])
|
@apiPack.route("/<id>/mod/add", methods=["POST"])
|
||||||
def addMod(id):
|
def addModEndpoint(id):
|
||||||
source = request.json.get("source", None)
|
source = request.json.get("source", None)
|
||||||
slug = request.json.get("slug", None)
|
slug = request.json.get("slug", None)
|
||||||
version = request.json.get("version", None)
|
version = request.json.get("version", None)
|
||||||
pack = {}
|
mod = addMod(id, source, slug, version)
|
||||||
mod = {}
|
|
||||||
|
|
||||||
if not os.path.exists(f"{PACKS_FOLDER}/{id}/packfile.json"):
|
if mod == "err_404":
|
||||||
return jsonify({"status": "error", "message": "pack not found"})
|
return jsonify({"status": "error", "message": "pack not found"})
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
elif mod == "err_source":
|
||||||
pack = json.load(fp)
|
|
||||||
fp.close()
|
|
||||||
mod_loader = pack.get("modloader").lower()
|
|
||||||
game_version = pack.get("version")
|
|
||||||
|
|
||||||
if not source:
|
|
||||||
return jsonify({"status": "error", "message": "mod source is required"})
|
return jsonify({"status": "error", "message": "mod source is required"})
|
||||||
if not slug:
|
elif mod == "err_slug":
|
||||||
return jsonify({"status": "error", "message": "mod slug is required"})
|
return jsonify({"status": "error", "message": "mod slug is required"})
|
||||||
|
elif mod == "err_exists":
|
||||||
for mod in pack["mods"]:
|
return jsonify({"status": "error", "message": "mod already exists"})
|
||||||
if mod.get("slug") == slug:
|
elif isinstance(mod, str):
|
||||||
return jsonify({"status": "error", "message": "mod already exists"})
|
return jsonify({"status": "error", "message": mod})
|
||||||
|
|
||||||
if source == "Modrinth":
|
|
||||||
mod = Modrinth.getModrinthMod(slug, version, mod_loader, game_version)
|
|
||||||
elif source == "CurseForge":
|
|
||||||
mod = CurseForge.getCurseForgeMod(slug, version, mod_loader, game_version)
|
|
||||||
|
|
||||||
if mod.get("status") != "ok":
|
|
||||||
return jsonify({"status": "error", "message": mod.get("message")})
|
|
||||||
|
|
||||||
pack["modpackVersion"] += 1
|
|
||||||
pack["mods"].append(mod.get("mod"))
|
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
|
|
||||||
json.dump(pack, fp)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"message": f"mod {mod.get("mod").get('title')} ({slug}) has been added",
|
"message": f"mod {mod.get("title")} ({slug}) has been added",
|
||||||
"mod": mod.get("mod"),
|
"mod": mod,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@apiPack.route("/<id>/mod/<slug>/delete", methods=["GET"])
|
@apiPack.route("/<id>/mod/<slug>/delete", methods=["GET"])
|
||||||
def deleteMod(id, slug):
|
def deleteModEndpoint(id, slug):
|
||||||
pack = {}
|
deleteMod(id, slug)
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
|
||||||
pack = json.load(fp)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
for mod in pack.get("mods"):
|
|
||||||
if mod.get("slug") == slug:
|
|
||||||
pack["mods"].remove(mod)
|
|
||||||
pack["modpackVersion"] += 1
|
|
||||||
if os.path.exists(
|
|
||||||
f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
|
||||||
):
|
|
||||||
os.remove(f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}")
|
|
||||||
|
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
|
|
||||||
json.dump(pack, fp)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
|
@ -138,34 +93,34 @@ def deleteMod(id, slug):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@apiPack.route("/<id>/mods/delete", methods=["POST"])
|
# @apiPack.route("/<id>/mods/delete", methods=["POST"])
|
||||||
def deleteModBulk(id):
|
# def deleteModBulk(id):
|
||||||
pack = {}
|
# pack = {}
|
||||||
slugs = request.json
|
# slugs = request.json
|
||||||
|
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
# with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
||||||
pack = json.load(fp)
|
# pack = json.load(fp)
|
||||||
fp.close()
|
# fp.close()
|
||||||
|
|
||||||
for slug in slugs:
|
# for slug in slugs:
|
||||||
for mod in pack.get("mods"):
|
# for mod in pack.get("mods"):
|
||||||
if mod.get("slug") == slug:
|
# if mod.get("slug") == slug:
|
||||||
pack["mods"].remove(mod)
|
# pack["mods"].remove(mod)
|
||||||
pack["modpackVersion"] += 1
|
# pack["modpackVersion"] += 1
|
||||||
if os.path.exists(
|
# if os.path.exists(
|
||||||
f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
# f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
||||||
):
|
# ):
|
||||||
os.remove(
|
# os.remove(
|
||||||
f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
# f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
||||||
)
|
# )
|
||||||
|
|
||||||
with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
|
# with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
|
||||||
json.dump(pack, fp)
|
# json.dump(pack, fp)
|
||||||
fp.close()
|
# fp.close()
|
||||||
|
|
||||||
return jsonify(
|
# return jsonify(
|
||||||
{
|
# {
|
||||||
"status": "ok",
|
# "status": "ok",
|
||||||
"message": f"mods has been removed",
|
# "message": f"mods has been removed",
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
|
|
@ -1,70 +1,37 @@
|
||||||
import os
|
|
||||||
from . import apiPacks
|
from . import apiPacks
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from config import PACKS_FOLDER
|
from shared.packs import getPacks, createPack, deletePack
|
||||||
import json
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
|
|
||||||
@apiPacks.route("/all", methods=["GET"])
|
@apiPacks.route("/all", methods=["GET"])
|
||||||
def getPacks():
|
def getPacksEndpoint():
|
||||||
packs = []
|
return jsonify(getPacks())
|
||||||
|
|
||||||
if not os.path.exists(f"{PACKS_FOLDER}"):
|
|
||||||
os.makedirs(f"{PACKS_FOLDER}", exist_ok=True)
|
|
||||||
return jsonify(packs)
|
|
||||||
|
|
||||||
pack_folders = [f.name for f in os.scandir(PACKS_FOLDER) if f.is_dir()]
|
|
||||||
for pack_folder in pack_folders:
|
|
||||||
if not os.path.exists(f"{PACKS_FOLDER}/{pack_folder}/packfile.json"):
|
|
||||||
continue
|
|
||||||
with open(f"{PACKS_FOLDER}/{pack_folder}/packfile.json") as fp:
|
|
||||||
pack = json.load(fp)
|
|
||||||
pack["_id"] = pack_folder
|
|
||||||
packs.append(pack)
|
|
||||||
fp.close()
|
|
||||||
return jsonify(packs)
|
|
||||||
|
|
||||||
|
|
||||||
@apiPacks.route("/new", methods=["POST"])
|
@apiPacks.route("/new", methods=["POST"])
|
||||||
def createPack():
|
def createPackEndpoint():
|
||||||
pack = {
|
pack, is_exists = createPack(
|
||||||
"formatVersion": 0,
|
request.json.get("title"),
|
||||||
"modpackVersion": 0,
|
request.json.get("author"),
|
||||||
"title": request.json.get("title"),
|
request.json.get("version"),
|
||||||
"author": request.json.get("author"),
|
request.json.get("modloader"),
|
||||||
"version": request.json.get("version"),
|
)
|
||||||
"modloader": request.json.get("modloader"),
|
|
||||||
"updateURL": "",
|
|
||||||
"mods": [],
|
|
||||||
}
|
|
||||||
title = pack.get("title").replace(" ", "_")
|
|
||||||
|
|
||||||
if os.path.exists(f"{PACKS_FOLDER}/{title}"):
|
if is_exists:
|
||||||
return jsonify({"status": "error", "message": "pack already exists"})
|
return jsonify({"status": "error", "message": "pack already exists"})
|
||||||
|
|
||||||
os.makedirs(f"{PACKS_FOLDER}/{title}", exist_ok=True)
|
|
||||||
|
|
||||||
with open(
|
|
||||||
os.path.abspath(f"{PACKS_FOLDER}/{title}/packfile.json"),
|
|
||||||
mode="w",
|
|
||||||
encoding="utf-8",
|
|
||||||
) as fp:
|
|
||||||
json.dump(pack, fp)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"message": f"pack {pack.get('title')} created",
|
"message": f"pack {pack.title} created",
|
||||||
"id": title,
|
"id": pack._id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@apiPacks.route("/<id>/delete", methods=["GET"])
|
@apiPacks.route("/<id>/delete", methods=["GET"])
|
||||||
def deletePack(id):
|
def deletePackEndpoint(id):
|
||||||
shutil.rmtree(f"{PACKS_FOLDER}/{id}")
|
deletePack(id)
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
|
|
0
src/shared/__init__.py
Normal file
0
src/shared/__init__.py
Normal file
46
src/shared/download.py
Normal file
46
src/shared/download.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import os
|
||||||
|
from flask_socketio import emit
|
||||||
|
import requests
|
||||||
|
from typing import Literal
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
|
def download(
|
||||||
|
path, url, name, total
|
||||||
|
) -> tuple[Literal[True], None] | tuple[Literal[False], str]:
|
||||||
|
if os.path.exists(f"{path}/{name}"):
|
||||||
|
return True, None
|
||||||
|
r = requests.get(url, stream=True)
|
||||||
|
if r.status_code != 200:
|
||||||
|
return False, f"Got a HTTP ERROR {r.status_code} while downloading {name}"
|
||||||
|
|
||||||
|
totalBytes = int(r.headers.get("Content-Length", total))
|
||||||
|
if os.getenv("is_cli"):
|
||||||
|
with open(f"{path}/{name}", "wb") as fp, tqdm(
|
||||||
|
desc=name.ljust(40),
|
||||||
|
total=totalBytes,
|
||||||
|
miniters=100,
|
||||||
|
unit="b",
|
||||||
|
unit_scale=True,
|
||||||
|
unit_divisor=1024,
|
||||||
|
) as bar:
|
||||||
|
for data in r.iter_content(chunk_size=1024):
|
||||||
|
size = fp.write(data)
|
||||||
|
bar.update(size)
|
||||||
|
else:
|
||||||
|
downloaded = 0
|
||||||
|
with open(f"{path}/{name}", "wb") as fp:
|
||||||
|
for data in r.iter_content(chunk_size=1024):
|
||||||
|
size = fp.write(data)
|
||||||
|
downloaded += size
|
||||||
|
emit(
|
||||||
|
"download_current",
|
||||||
|
{
|
||||||
|
"status": "pending",
|
||||||
|
"total_bytes": totalBytes,
|
||||||
|
"download_bytes": downloaded,
|
||||||
|
},
|
||||||
|
namespace="/",
|
||||||
|
broadcast=True,
|
||||||
|
)
|
||||||
|
return True, None
|
91
src/shared/pack.py
Normal file
91
src/shared/pack.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import os
|
||||||
|
from config import PACKS_FOLDER
|
||||||
|
import json
|
||||||
|
from type.pack import Pack
|
||||||
|
from type.mod import Mod
|
||||||
|
from typing import Literal
|
||||||
|
from api.source import Modrinth, CurseForge
|
||||||
|
|
||||||
|
|
||||||
|
def getPack(id: str) -> Pack | None:
|
||||||
|
if not os.path.exists(f"{PACKS_FOLDER}/{id}/packfile.json"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
pack: Pack = {}
|
||||||
|
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
||||||
|
pack = json.load(fp)
|
||||||
|
pack["_id"] = id
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return pack
|
||||||
|
|
||||||
|
|
||||||
|
def addMod(
|
||||||
|
pack_id: str, source: str, slug: str, version: str | None
|
||||||
|
) -> (
|
||||||
|
Mod
|
||||||
|
| Literal["err_404"]
|
||||||
|
| Literal["err_source"]
|
||||||
|
| Literal["err_slug"]
|
||||||
|
| Literal["err_exists"]
|
||||||
|
| str
|
||||||
|
):
|
||||||
|
pack: Pack = {}
|
||||||
|
mod: Mod = {}
|
||||||
|
|
||||||
|
if not os.path.exists(f"{PACKS_FOLDER}/{pack_id}/packfile.json"):
|
||||||
|
return "err_404"
|
||||||
|
with open(f"{PACKS_FOLDER}/{pack_id}/packfile.json") as fp:
|
||||||
|
pack = json.load(fp)
|
||||||
|
fp.close()
|
||||||
|
mod_loader = pack.get("modloader").lower()
|
||||||
|
game_version = pack.get("version")
|
||||||
|
|
||||||
|
if not source:
|
||||||
|
return "err_source"
|
||||||
|
if not slug:
|
||||||
|
return "err_slug"
|
||||||
|
|
||||||
|
for mod in pack["mods"]:
|
||||||
|
if mod.get("slug") == slug:
|
||||||
|
return "err_exists"
|
||||||
|
|
||||||
|
if source == "Modrinth":
|
||||||
|
mod = Modrinth.getModrinthMod(slug, version, mod_loader, game_version)
|
||||||
|
elif source == "CurseForge":
|
||||||
|
mod = CurseForge.getCurseForgeMod(slug, version, mod_loader, game_version)
|
||||||
|
|
||||||
|
if mod.get("status") != "ok":
|
||||||
|
return mod.get("message")
|
||||||
|
|
||||||
|
pack["modpackVersion"] += 1
|
||||||
|
pack["mods"].append(mod.get("mod"))
|
||||||
|
with open(
|
||||||
|
f"{PACKS_FOLDER}/{pack_id}/packfile.json", mode="w", encoding="utf-8"
|
||||||
|
) as fp:
|
||||||
|
json.dump(pack, fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return mod.get("mod")
|
||||||
|
|
||||||
|
|
||||||
|
def deleteMod(id: str, slug: str) -> Literal[True]:
|
||||||
|
pack = {}
|
||||||
|
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
|
||||||
|
pack = json.load(fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
for mod in pack.get("mods"):
|
||||||
|
if mod.get("slug") == slug:
|
||||||
|
pack["mods"].remove(mod)
|
||||||
|
pack["modpackVersion"] += 1
|
||||||
|
if os.path.exists(
|
||||||
|
f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
|
||||||
|
):
|
||||||
|
os.remove(f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}")
|
||||||
|
|
||||||
|
with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
|
||||||
|
json.dump(pack, fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return True
|
61
src/shared/packs.py
Normal file
61
src/shared/packs.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import os
|
||||||
|
from config import PACKS_FOLDER
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from type.pack import Pack
|
||||||
|
|
||||||
|
|
||||||
|
def getPacks() -> list[Pack]:
|
||||||
|
"""
|
||||||
|
Lists and returns all available packs from PACKS_FOLDER directory defined in config.py
|
||||||
|
"""
|
||||||
|
packs: list[Pack] = []
|
||||||
|
|
||||||
|
if not os.path.exists(f"{PACKS_FOLDER}"):
|
||||||
|
os.makedirs(f"{PACKS_FOLDER}", exist_ok=True)
|
||||||
|
return packs
|
||||||
|
|
||||||
|
pack_folders = [f.name for f in os.scandir(PACKS_FOLDER) if f.is_dir()]
|
||||||
|
for pack_folder in pack_folders:
|
||||||
|
if not os.path.exists(f"{PACKS_FOLDER}/{pack_folder}/packfile.json"):
|
||||||
|
continue
|
||||||
|
with open(f"{PACKS_FOLDER}/{pack_folder}/packfile.json") as fp:
|
||||||
|
pack = json.load(fp)
|
||||||
|
pack["_id"] = pack_folder
|
||||||
|
packs.append(pack)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return packs
|
||||||
|
|
||||||
|
|
||||||
|
def createPack(
|
||||||
|
title: str, author: str, game_version: str, mod_loader: str
|
||||||
|
) -> tuple[Pack, bool]:
|
||||||
|
"""
|
||||||
|
Creates a new pack.
|
||||||
|
If pack exists returns tuple[Pack, True], if pack was created returns tuple[Pack, False]
|
||||||
|
"""
|
||||||
|
pack = Pack(
|
||||||
|
title.replace(" ", "_"), title, author, game_version, mod_loader, "", [], 0, 0
|
||||||
|
)
|
||||||
|
|
||||||
|
if os.path.exists(f"{PACKS_FOLDER}/{pack._id}"):
|
||||||
|
return pack, True
|
||||||
|
|
||||||
|
os.makedirs(f"{PACKS_FOLDER}/{pack._id}", exist_ok=True)
|
||||||
|
|
||||||
|
with open(
|
||||||
|
os.path.abspath(f"{PACKS_FOLDER}/{pack._id}/packfile.json"),
|
||||||
|
mode="w",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as fp:
|
||||||
|
json.dump(pack.json(), fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return pack, False
|
||||||
|
|
||||||
|
|
||||||
|
def deletePack(id):
|
||||||
|
shutil.rmtree(f"{PACKS_FOLDER}/{id}")
|
||||||
|
return True
|
0
src/type/__init__.py
Normal file
0
src/type/__init__.py
Normal file
21
src/type/file.py
Normal file
21
src/type/file.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class ModFile:
|
||||||
|
def __init__(
|
||||||
|
self, version: str, hashes: dict[str, str], url: str, filename: str, size: int
|
||||||
|
):
|
||||||
|
self.version = version
|
||||||
|
self.hashes = hashes
|
||||||
|
self.url = url
|
||||||
|
self.filename = filename
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
return {
|
||||||
|
"version": self.version,
|
||||||
|
"hashes": self.hashes,
|
||||||
|
"url": self.url,
|
||||||
|
"filename": self.filename,
|
||||||
|
"size": self.size,
|
||||||
|
}
|
39
src/type/mod.py
Normal file
39
src/type/mod.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import json
|
||||||
|
from .file import ModFile
|
||||||
|
|
||||||
|
|
||||||
|
class Mod:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
slug: str,
|
||||||
|
project_id: str,
|
||||||
|
icon: str,
|
||||||
|
title: str,
|
||||||
|
developers: list[str],
|
||||||
|
source: str,
|
||||||
|
environment: dict[str, bool],
|
||||||
|
dependencies: list,
|
||||||
|
file: ModFile,
|
||||||
|
):
|
||||||
|
self.slug = slug
|
||||||
|
self.project_id = project_id
|
||||||
|
self.icon = icon
|
||||||
|
self.title = title
|
||||||
|
self.developers = developers
|
||||||
|
self.source = source
|
||||||
|
self.environment = environment
|
||||||
|
self.dependencies = dependencies
|
||||||
|
self.file = file
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
return {
|
||||||
|
"slug": self.slug,
|
||||||
|
"project_id": self.project_id,
|
||||||
|
"icon": self.icon,
|
||||||
|
"title": self.title,
|
||||||
|
"developers": self.developers,
|
||||||
|
"source": self.source,
|
||||||
|
"environment": self.environment,
|
||||||
|
"dependencies": self.dependencies,
|
||||||
|
"file": self.file,
|
||||||
|
}
|
38
src/type/pack.py
Normal file
38
src/type/pack.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import json
|
||||||
|
from .mod import Mod
|
||||||
|
|
||||||
|
|
||||||
|
class Pack:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
_id: str,
|
||||||
|
title: str,
|
||||||
|
author: str,
|
||||||
|
version: str,
|
||||||
|
modloader: str,
|
||||||
|
updateURL: str,
|
||||||
|
mods: list[Mod],
|
||||||
|
modpackVersion: int = 0,
|
||||||
|
formatVersion: int = 0,
|
||||||
|
):
|
||||||
|
self._id = _id
|
||||||
|
self.title = title
|
||||||
|
self.author = author
|
||||||
|
self.version = version
|
||||||
|
self.modloader = modloader
|
||||||
|
self.updateURL = updateURL
|
||||||
|
self.mods = mods
|
||||||
|
self.modpackVersion = modpackVersion
|
||||||
|
self.formatVersion = formatVersion
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
return {
|
||||||
|
"title": self.title,
|
||||||
|
"author": self.author,
|
||||||
|
"version": self.version,
|
||||||
|
"modloader": self.modloader,
|
||||||
|
"updateURL": self.updateURL,
|
||||||
|
"mods": self.mods,
|
||||||
|
"modpackVersion": self.modpackVersion,
|
||||||
|
"formatVersion": self.formatVersion,
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue