83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING
|
|
|
|
from .library import Mod, LibraryError
|
|
|
|
if TYPE_CHECKING:
|
|
from .manager import Manager
|
|
|
|
def export_modpack(manager: Manager, dest_path: Path, profile_name: str) -> None:
|
|
profile = manager.profiles.data.get(profile_name)
|
|
if not profile:
|
|
raise ValueError(f"Profile {profile_name} not found")
|
|
|
|
with zipfile.ZipFile(dest_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
# Export profile metadata
|
|
zf.writestr("modpack.json", json.dumps({"name": profile_name, "profile": profile}, indent=2))
|
|
|
|
# Export mods
|
|
mods_to_export = set(profile["order"])
|
|
for mod_id in mods_to_export:
|
|
mod = manager.library.get(mod_id)
|
|
if not mod:
|
|
continue
|
|
|
|
# Write mod files
|
|
mod_root = mod.root
|
|
for dirpath, dirnames, filenames in os.walk(mod_root):
|
|
for filename in filenames:
|
|
file_path = Path(dirpath) / filename
|
|
rel_path = file_path.relative_to(mod_root)
|
|
zf.write(file_path, f"mods/{mod_id}/{rel_path}")
|
|
|
|
def import_modpack(manager: Manager, source_path: Path, new_profile_name: str) -> list[str]:
|
|
with zipfile.ZipFile(source_path, "r") as zf:
|
|
try:
|
|
with zf.open("modpack.json") as f:
|
|
data = json.load(f)
|
|
profile = data.get("profile")
|
|
except KeyError:
|
|
raise ValueError("Not a valid modpack: missing modpack.json")
|
|
|
|
if not profile:
|
|
raise ValueError("Invalid modpack.json")
|
|
|
|
# Extract mods
|
|
extracted_mods = []
|
|
for name in zf.namelist():
|
|
if name.startswith("mods/") and len(name.split("/")) > 2:
|
|
parts = name.split("/")
|
|
mod_id = parts[1]
|
|
if mod_id not in manager.library.mods:
|
|
# Not in library, we need to extract it
|
|
dest_file = manager.paths.mods_dir / Path(*parts[1:])
|
|
dest_file.parent.mkdir(parents=True, exist_ok=True)
|
|
if not name.endswith("/"):
|
|
with zf.open(name) as source, open(dest_file, "wb") as target:
|
|
shutil.copyfileobj(source, target)
|
|
if mod_id not in extracted_mods:
|
|
extracted_mods.append(mod_id)
|
|
|
|
# Reload library to discover the new mods
|
|
manager.reload_library()
|
|
|
|
# Ensure profile name is unique
|
|
final_name = new_profile_name
|
|
n = 2
|
|
while final_name in manager.profiles.data:
|
|
final_name = f"{new_profile_name} ({n})"
|
|
n += 1
|
|
|
|
manager.profiles.data[final_name] = profile
|
|
manager.profiles.switch(final_name)
|
|
manager.profiles.save()
|
|
|
|
return extracted_mods
|