Skip to content
This repository has been archived by the owner on Oct 27, 2024. It is now read-only.

Commit

Permalink
Merge pull request #14 from tygoee/dev
Browse files Browse the repository at this point in the history
Merge dev and main
  • Loading branch information
tygoee authored Mar 6, 2024
2 parents 14beb8d + 4584361 commit 43eab99
Show file tree
Hide file tree
Showing 17 changed files with 514 additions and 130 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,7 @@ cython_debug/

# Installation dirs
.minecraft/
gamedir/
gamedir/

# Temporary dirs for testing
tests/temp/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Minecraft modpack manager - This solves the problem of having to install mods manually. Currently, you need to edit the file manually, as this is still in it's alpha phase. You can currently download mods from curseforge, modrinth and planet minecraft and custom urls. You can also install forge automatically. Currently, mods, resourcepacks and shaderpacks are supported.

## "Building" to a `.pyz` file
## Building to a `.pyz` file

How to make a `.pyz` file:

Expand Down
38 changes: 7 additions & 31 deletions share/modpacks/example-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
{
"type": "cf",
"slug": "animal-feeding-through",
"slug": "animal-feeding-trough",
"name": "animal_feeding_trough-1.0.3%2B1.20.1-forge.jar",
"id": 4606793
},
Expand Down Expand Up @@ -199,12 +199,6 @@
"name": "collective-1.20.1-6.65.jar",
"id": 4639343
},
{
"type": "cf",
"slug": "colorful-goats",
"name": "ColourfulGoats-1.20.1-1.3.jar",
"id": 4646063
},
{
"type": "cf",
"slug": "combat-roll",
Expand Down Expand Up @@ -289,12 +283,6 @@
"name": "eatinganimation-1.20-5.0.0.jar",
"id": 4576004
},
{
"type": "cf",
"slug": "elytra-bombing",
"name": "ElytraBombing-Forge-1.20.1-1.0.0.jar",
"id": 4654598
},
{
"type": "cf",
"slug": "enchantment-transfer",
Expand Down Expand Up @@ -498,8 +486,8 @@
{
"type": "cf",
"slug": "selene",
"name": "moonlight-1.20-2.8.0j-forge.jar",
"id": 4701796
"name": "moonlight-1.20-2.8.7-forge.jar",
"id": 4719245
},
{
"type": "cf",
Expand Down Expand Up @@ -630,12 +618,6 @@
"name": "rubidium-0.6.5.jar",
"id": 4573226
},
{
"type": "cf",
"slug": "better-ladder-placements",
"name": "Salju-Ladders-2.4.2.jar",
"id": 4670468
},
{
"type": "cf",
"slug": "selectable-painting",
Expand All @@ -657,21 +639,15 @@
{
"type": "cf",
"slug": "small-ships",
"name": "smallships-forge-1.20.1-2.0.0-a2.3.3.jar",
"id": 4645815
"name": "smallships-forge-1.20.1-2.0.0-b1.1.jar",
"id": 5148122
},
{
"type": "cf",
"slug": "hellions-sniffer",
"name": "Sniffer%2B-forge-1.20.1-0.2.0.jar",
"id": 4591535
},
{
"type": "cf",
"slug": "snow-real-magic",
"name": "SnowRealMagic-1.20.1-forge-9.0.1.jar",
"id": 4669207
},
{
"type": "cf",
"slug": "snow-under-trees",
Expand Down Expand Up @@ -753,8 +729,8 @@
{
"type": "cf",
"slug": "treechop",
"name": "TreeChop-1.20.1-forge-0.18.3.jar",
"id": 4685647
"name": "TreeChop-1.20.1-fabric-0.18.8.jar",
"id": 5044579
},
{
"type": "cf",
Expand Down
Empty file added src/apis/__init__.py
Empty file.
251 changes: 251 additions & 0 deletions src/apis/fabric_meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
# MCM-Manager: Minecraft Modpack Manager
# Copyright (C) 2023 Tygo Everts
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from json import loads
from typing import Literal, Optional, overload
from urllib import request
from http.client import HTTPResponse
from ..typings import (
# Versions
GameVersion, IntermediaryVersion,
YarnVersion, AllVersions,

# Loader
FabricVersionJson, LoaderJson, InstallerLibrary, LibraryList
)

from ..common.maven_coords import maven_parse


def api_url(url: str, *paths: str) -> str:
if not url[-1] == '/':
url += '/'

return url + '/'.join(paths)


# Types are not defined because these endpoints are unused
class versions:
def __init__(self, game_version: Optional[str] = None) -> None:
"""
Creates a fabric-meta versions object.
:param game_version: The minecraft version to select
"""

self.game_version = game_version
self._base_url = "https://meta.fabricmc.net/v2/versions/"

def all(self) -> AllVersions:
"Full database, includes all the data. Warning: large JSON."

url = api_url(self._base_url)
response: HTTPResponse = request.urlopen(url)

return loads(response.read())

def yarn(self) -> list[YarnVersion]:
"""
Lists all of the yarn versions, stable is based on the Minecraft version.
When `game_version` is specified, it lists all of the yarn versions for the provided game version.
"""

if self.game_version is None:
url = api_url(self._base_url, 'yarn')
else:
url = api_url(self._base_url, 'yarn', self.game_version)

response: HTTPResponse = request.urlopen(url)

return loads(response.read())

def intermediary(self) -> list[IntermediaryVersion]:
"""
Lists all of the intermediary versions, stable is based of the Minecraft version.
When `game_version` is specified, it only lists the provided game version.
"""

if self.game_version is None:
url = api_url(self._base_url, 'intermediary')
else:
url = api_url(self._base_url, 'intermediary', self.game_version)

response: HTTPResponse = request.urlopen(url)

return loads(response.read())


class game:
def __init__(self) -> None:
"Creates a fabric-meta game versions object"

self._base_url = "https://meta.fabricmc.net/v2/versions/game/"

def all(self) -> list[GameVersion]:
"Lists all of the supported game versions."

url = api_url(self._base_url)
response: HTTPResponse = request.urlopen(url)

return loads(response.read())

def yarn(self) -> list[GameVersion]:
"Lists all of the compatible game versions for yarn."

url = api_url(self._base_url, 'yarn')
response: HTTPResponse = request.urlopen(url)

return loads(response.read())

def intermediary(self) -> list[GameVersion]:
"Lists all of the compatible game versions for intermediary."

url = api_url(self._base_url, 'intermediary')
response: HTTPResponse = request.urlopen(url)

return loads(response.read())


class loader:
@overload
def __init__(
self, game_version: str,
loader_version: Optional[str] = None
) -> None:
"""
Creates a fabric-meta loader object.
To get the result, use `loader.result`.
For other values, use `loader`, `intermediary` and `launcher_meta`
:param game_version: The minecraft version to select
:param loader_version: The fabric loader version to select
"""

@overload
def __init__(
self, game_version: Optional[str] = None
) -> None:
"""
Creates a fabric-meta loader object.
To get the result, use `loader.result`.
For other values, use `loader`, `intermediary` and `launcher_meta`
:param game_version: The minecraft version to select
"""

def __init__(
self, game_version: Optional[str] = None,
loader_version: Optional[str] = None
) -> None:
"""
Creates a fabric-meta loader object.
To get the result, use `loader.result`.
For other values, use `loader`, `intermediary` and `launcher_meta`
:param game_version: The minecraft version to select
:param loader_version: The fabric loader version to select
"""

self.game_version = game_version
self.loader_version = loader_version
self._complete = False

base_url = "https://meta.fabricmc.net/v2/versions/loader/"

if game_version is None and loader_version is None:
self._url = base_url
elif game_version is not None and loader_version is None:
self._url = api_url(base_url, game_version)
elif game_version is not None and loader_version is not None:
self._complete = True
self._url = api_url(base_url, game_version, loader_version)
else:
raise ValueError(
"'loader_version' may not be passed when 'game_version' is None"
)

response: HTTPResponse = request.urlopen(api_url(self._url))
self.result: LoaderJson = loads(response.read().decode('utf-8'))

self.loader = self.result['loader']
self.intermediary = self.result['intermediary']
self.launcher_meta = self.result['launcherMeta']

def libraries(
self, launcher_dir: str,
side: Optional[Literal['client', 'server']] = None,
extra: list[InstallerLibrary] = []
) -> LibraryList:
"Lists all of the libraries"
libs: LibraryList = []

for lib_type in self.result['launcherMeta']['libraries'].keys():
if (lib_type not in ('client', 'common', 'server') or not
(side in (None, lib_type) or lib_type == 'common')):
continue

for lib in self.result['launcherMeta']['libraries'][lib_type] + extra:
maven = maven_parse(lib['name'])
libs.append({
'name': lib['name'],
'url': maven.to_url(lib['url']),
'file': maven.to_file(launcher_dir, 'libraries')
})

return libs

def profile_json(self) -> FabricVersionJson:
"Returns the JSON file that should be used in the standard Minecraft launcher."

if not self._complete:
raise ValueError(
"Cannot fetch profile json if 'game_version' "
"and 'loader_version' isn't specified"
)

url = api_url(self._url, 'profile', 'json')
response: HTTPResponse = request.urlopen(url)

return loads(response.read().decode('utf-8'))

def profile_zip(self) -> bytes:
"Downloads a zip file with the launcher's profile json, and the dummy jar. To be extracted into .minecraft/versions"
if not self._complete:
raise ValueError(
"Cannot fetch profile zip if 'game_version' "
"and 'loader_version' isn't specified"
)

url = api_url(self._url, 'profile', 'zip')
response: HTTPResponse = request.urlopen(url)

return response.read()

def server_json(self) -> bytes:
"Returns the JSON file in format of the launcher JSON, but with the server's main class."
if not self._complete:
raise ValueError(
"Cannot fetch server json if 'game_version' "
"and 'loader_version' isn't specified"
)

url = api_url(self._url, 'server', 'json')
response: HTTPResponse = request.urlopen(url)

return response.read()
28 changes: 19 additions & 9 deletions src/install/headers.py → src/apis/piston_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

# The headers to mimic a common browser user agent
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1"
}
from http.client import HTTPResponse
from json import loads
from urllib import request


from ..typings import MinecraftJson

version_manifest_v2 = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"


def get_minecraft_json(mc_version: str) -> MinecraftJson:
"""Get the minecraft json from a minecraft"""
res: HTTPResponse = request.urlopen(version_manifest_v2)
for item in loads(res.read().decode('utf-8'))['versions']:
if item['id'] == mc_version:
res = request.urlopen(item['url'])
return loads(res.read().decode('utf-8'))

raise KeyError("Couldn't find minecraft version in version manifest")
Loading

0 comments on commit 43eab99

Please sign in to comment.