mc-get/mc-get.py

200 lines
7.8 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import argparse
import api
import mcfs
import os
import mcgetdb
from colorama import Fore, Style
db = mcgetdb.McGetDB(mcfs.mc_dir)
def validate():
raise NotImplementedError
def download_cache(url: str, filename: str, size: int):
cache_file_path = os.path.join(mcfs.cache_dir, filename)
if not mcfs.is_path_exist(mcfs.cache_dir):
os.mkdir(mcfs.cache_dir)
if not mcfs.is_path_exist(cache_file_path):
api.download(url, size, cache_file_path)
else:
print(f"{filename} is in cache.")
return filename
def modpack_install(filename: str):
modpack = mcfs.get_modpack_info(filename)
print(f"{Fore.YELLOW}Installing {modpack.name} modpack...{Style.RESET_ALL}")
for file in modpack.files:
path = file["path"].split("/")
downloads = file["downloads"]
print(file["path"])
download_cache(downloads[0], path[1], file["fileSize"])
mcfs.install(path[1], path[0])
print(f"{Fore.YELLOW}Overriding...{Style.RESET_ALL}")
mcfs.install_modpacks_override(filename)
def install(projects: list, version, loader):
to_install = []
dependencies_to_install = []
not_found = []
unavailable = []
projects_ids = []
def check_project(slug):
id = api.check_project(project=slug)
if id:
projects_ids.append(id.id)
else:
not_found.append(slug)
def dependency_solver(ver):
for dependency in ver.dependencies:
if dependency["dependency_type"] in ["optional", "embedded"]:
continue
if dependency["version_id"]:
dep_ver = api.version(version=dependency["version_id"])
else:
dep_ver = api.get_versions(project=dependency["project_id"], loaders=f'["{loader}"]',
game_versions=f'["{mc_ver}"]')[0]
if dependency["project_id"]:
proj_id = dependency["project_id"]
else:
proj_id = dep_ver.project_id
if proj_id in projects_ids or proj_id in [dep_proj.id for dep_proj, _ in dependencies_to_install]:
continue
project_data = api.project(project=proj_id)
dependencies_to_install.append((project_data, dep_ver))
dependency_solver(dep_ver)
for project in projects:
check_project(project)
for project in projects_ids:
project_data = api.project(project=project)
versions = api.get_versions(project=project, loaders=f'["{loader}"]',
game_versions=f'["{mc_ver}"]')
if versions:
to_install.append((project_data, versions[0]))
dependency_solver(versions[0])
else:
unavailable.append(project_data)
print("To install:", *[project.title + " " + version.version_number for project, version in to_install], sep="\n\t")
if dependencies_to_install:
print("With dependencies:",
*[project.title + " " + version.version_number for project, version in dependencies_to_install],
sep="\n\t")
if not_found:
print("Not found: ", end="")
print(*[project for project in not_found], sep=", ")
if unavailable:
print("Cannot be installed:", *[project.title for project in unavailable], sep="\n\t")
choose = input("Continue? [y/n]")
if choose.strip().lower() in ["n", "no"]:
print("Canceled.")
return
for project, version in to_install + dependencies_to_install:
file = type("mc_file", (object,), version.files[0])
filename = project.slug + ".jar"
download_cache(file.url, filename, file.size)
match project.project_type:
case "resourcepack":
subdir = "resourcepacks"
case "mod":
subdir = "mods"
case "shader":
subdir = "shaderpacks"
case "modpack":
modpack_install(filename)
continue
case _:
raise NotImplementedError
mcfs.install(filename, subdir)
def search(query: list):
results = api.search(query=' '.join(query))
for result in results.hits:
print(Fore.GREEN, end="")
print(result.get("slug", "error"), end="")
print(Style.RESET_ALL, end="")
print(f' [{result.get("project_type", "error")}] ', end="")
print(
f' : {Fore.GREEN}{result.get("title", "error")}{Style.RESET_ALL} --- {result.get("description", "error")}')
def clean():
if mcfs.is_path_exist(mcfs.cache_dir):
files = os.listdir(mcfs.cache_dir)
if len(files) > 0:
for file in files:
os.remove(os.path.join(mcfs.cache_dir, file))
print("Cache cleared successfully.")
return
print("Nothing to clear.")
if __name__ == "__main__":
def __select_version(versions):
if len(versions) > 0:
print("Installed MC versions: ")
for id, version in enumerate(versions):
print(id + 1, version.version_number + (f" with {version.modloader}" if version.is_modified else ""),
sep=": ")
if len(versions) > 1:
id_to_use = -1
while id_to_use not in range(1, len(versions)):
id_input = input(f"Select MC version to use [1-{len(versions)}]: ")
if not id_input.isnumeric():
continue
id_to_use = int(id_input)
else:
id_to_use = 1
selected_version = versions[id_to_use - 1]
print("Selected MC version:", selected_version.version_number +
(f" with {selected_version.modloader}" if selected_version.is_modified else ""))
return selected_version
properties = db.get_properties()
if not properties:
version_to_use = __select_version(mcfs.get_installed_mc_versions())
if version_to_use.is_modified: # TODO: Добавить иерархию каталогов
db.set_properties(version_to_use.version_number, version_to_use.modloader)
else:
db.set_properties(version_to_use.version_number)
properties = db.get_properties()
print(properties)
_, mc_ver, loader, _ = properties
desc = "Minecraft mods packet manager based on Modrinth API"
parser = argparse.ArgumentParser(description=desc,
formatter_class=argparse.RawTextHelpFormatter)
subparsers = parser.add_subparsers(dest="method",
required=True) # Переменная, в которую будет записано имя подкоманды
parser_install = subparsers.add_parser("install", help="Install one or more mods or resources")
parser_install.add_argument("projects", nargs="+")
parser_install.add_argument("--version", default=mc_ver)
parser_install.add_argument("--loader", default=loader)
parser_search = subparsers.add_parser("search", help="Find a mod or a resource")
parser_search.add_argument("query", nargs="+")
parser_validate = subparsers.add_parser("validate", help="Validate the installation")
parser_clean = subparsers.add_parser("clean", help="Clean the cache of this program")
kwargs = vars(parser.parse_args()) # Получаем все поля получившегося Namespace и пихаем в словарь
globals()[kwargs.pop("method")](**kwargs) # Из глобального контекста получаем функцию с названием как в method,
# заодно вытаскивая название метода из списка аргументов,
# затем вызываем функцию с распакованным словарём в качестве аргумента