mc-get/mc-get.py

215 lines
8.5 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)
match project_data.project_type:
case "resourcepack":
versions = api.get_versions(project=project, game_versions=f'["{mc_ver}"]')
case "mod":
versions = api.get_versions(project=project, loaders=f'["{loader}"]', game_versions=f'["{mc_ver}"]')
case "shader": # TODO: Реализовать поддержку загрузчиков шейдеров
versions = api.get_versions(project=project, game_versions=f'["{mc_ver}"]')
case "modpack": # TODO: [РЕГРЕССИЯ] Реализовать поддержку модпаков
raise NotImplementedError
case _:
raise NotImplementedError
if versions:
to_install.append((project_data, versions[0]))
dependency_solver(versions[0])
else:
unavailable.append(project_data)
if to_install:
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")
all_to_install = to_install + dependencies_to_install
if not all_to_install:
return
choose = input("Continue? [y/n] ")
if choose.strip().lower() in ["n", "no"]:
print("Canceled.")
return
for project, version in all_to_install:
file = type("mc_file", (object,), version.files[0])
filename = file.filename
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,
# заодно вытаскивая название метода из списка аргументов,
# затем вызываем функцию с распакованным словарём в качестве аргумента