mcserver-cli 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcserver/__init__.py +1 -0
- mcserver/__main__.py +3 -0
- mcserver/app.py +24 -0
- mcserver/caching.py +0 -0
- mcserver/cli.py +326 -0
- mcserver/commands/__init__.py +39 -0
- mcserver/commands/add_projects.py +7 -0
- mcserver/commands/import_setup.py +6 -0
- mcserver/commands/initialize_server.py +119 -0
- mcserver/commands/list_projects.py +6 -0
- mcserver/commands/op_grant.py +7 -0
- mcserver/commands/op_list.py +32 -0
- mcserver/commands/op_revoke.py +7 -0
- mcserver/commands/print_help.py +7 -0
- mcserver/commands/remove_projects.py +6 -0
- mcserver/commands/search_projects.py +7 -0
- mcserver/commands/server_status.py +6 -0
- mcserver/commands/show_projects.py +26 -0
- mcserver/commands/start_server.py +150 -0
- mcserver/commands/stop_server.py +46 -0
- mcserver/commands/update_projects.py +6 -0
- mcserver/commands/whitelist_add.py +7 -0
- mcserver/commands/whitelist_list.py +31 -0
- mcserver/commands/whitelist_remove.py +31 -0
- mcserver/commandsa.py +1297 -0
- mcserver/config.py +37 -0
- mcserver/constants.py +14 -0
- mcserver/fabricmc/meta.py +41 -0
- mcserver/legacyfabric/meta.py +37 -0
- mcserver/metadata.py +33 -0
- mcserver/minecraft/api.py +94 -0
- mcserver/minecraft/player_identity.py +21 -0
- mcserver/modrinth/api.py +657 -0
- mcserver/modrinth/modpack.py +101 -0
- mcserver/modrinth/project_records/metadata.py +0 -0
- mcserver/modrinth/project_records/relationships.py +203 -0
- mcserver/modrinth/project_records/shared.py +9 -0
- mcserver/modrinth/projects.py +80 -0
- mcserver/modrinth/shared.py +13 -0
- mcserver/modrinth/slug_index.py +36 -0
- mcserver/mojang/eula.py +28 -0
- mcserver/mojang/manifest.py +69 -0
- mcserver/mysterious.py +5 -0
- mcserver/networking.py +152 -0
- mcserver/papermc/api.py +81 -0
- mcserver/purpurmc/api.py +81 -0
- mcserver/quiltmc/meta.py +54 -0
- mcserver/resolver.py +164 -0
- mcserver/server_files/banned_ips.py +120 -0
- mcserver/server_files/banned_players.py +166 -0
- mcserver/server_files/ops.py +143 -0
- mcserver/server_files/properties.py +41 -0
- mcserver/server_files/usercaches.py +0 -0
- mcserver/server_files/whitelist.py +163 -0
- mcserver/shared.py +198 -0
- mcserver/state.py +77 -0
- mcserver_cli-3.0.0.dist-info/METADATA +63 -0
- mcserver_cli-3.0.0.dist-info/RECORD +61 -0
- mcserver_cli-3.0.0.dist-info/WHEEL +4 -0
- mcserver_cli-3.0.0.dist-info/entry_points.txt +2 -0
- mcserver_cli-3.0.0.dist-info/licenses/LICENSE +9 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
import zipfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal, NotRequired, TypedDict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# TYpedDict
|
|
10
|
+
class FileHashes(TypedDict):
|
|
11
|
+
sha1: str # original: sha1
|
|
12
|
+
sha512: str # original: sha512
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ModEnvironment(TypedDict):
|
|
16
|
+
client_side: Literal[
|
|
17
|
+
"required", "optional", "unsupported", "unknown"
|
|
18
|
+
] # original: client
|
|
19
|
+
server_side: Literal[
|
|
20
|
+
"required", "optional", "unsupported", "unknown"
|
|
21
|
+
] # original: server
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ModpackFile(TypedDict):
|
|
25
|
+
file_path: Path # original: path
|
|
26
|
+
hashes: FileHashes # original: hashes
|
|
27
|
+
mod_environment: NotRequired[ModEnvironment] # original: env
|
|
28
|
+
download_urls: list[str] # original: downloads
|
|
29
|
+
file_size: int # original: fileSize
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ModpackIndex(TypedDict):
|
|
33
|
+
format_version: int # original: formatVersion
|
|
34
|
+
game_name: Literal["minecraft"] # original: game
|
|
35
|
+
version_id: str # original: versionId
|
|
36
|
+
pack_name: str # original: name
|
|
37
|
+
summary: NotRequired[str] # original: summary
|
|
38
|
+
files: list[ModpackFile] # original: files
|
|
39
|
+
dependencies: dict[str, str] # original: dependencies
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Functions
|
|
43
|
+
def read_index(file_path: Path | str) -> ModpackIndex:
|
|
44
|
+
file_path = Path(file_path)
|
|
45
|
+
|
|
46
|
+
pack_index = {}
|
|
47
|
+
with zipfile.ZipFile(file_path) as zip_file:
|
|
48
|
+
pack_index = json.loads(zip_file.read("modrinth.index.json").decode())
|
|
49
|
+
|
|
50
|
+
files = []
|
|
51
|
+
for file in pack_index["files"]:
|
|
52
|
+
files.append(
|
|
53
|
+
{
|
|
54
|
+
"file_path": Path(file["path"]),
|
|
55
|
+
"hashes": file["hashes"],
|
|
56
|
+
"mod_environment": file.get("env"),
|
|
57
|
+
"download_urls": file["downloads"],
|
|
58
|
+
"file_size": file["fileSize"],
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
"format_version": pack_index["formatVersion"],
|
|
64
|
+
"game_name": pack_index["game"],
|
|
65
|
+
"version_id": pack_index["versionId"],
|
|
66
|
+
"pack_name": pack_index["name"],
|
|
67
|
+
"summary": pack_index.get("summary"),
|
|
68
|
+
"files": files,
|
|
69
|
+
"dependencies": pack_index["dependencies"],
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _extract_zip(
|
|
74
|
+
zip_file: zipfile.ZipFile, zip_path: str, path: Path | str = Path.cwd()
|
|
75
|
+
):
|
|
76
|
+
path = Path(path)
|
|
77
|
+
for entry in zip_file.namelist():
|
|
78
|
+
if not entry.startswith(zip_path):
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
destination_path = path / entry.removeprefix(zip_path)
|
|
82
|
+
destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
if entry.endswith("/"):
|
|
85
|
+
destination_path.mkdir(exist_ok=True)
|
|
86
|
+
else:
|
|
87
|
+
destination_path.write_bytes(zip_file.read(entry))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def apply_overrides(file_path: str | Path) -> None:
|
|
91
|
+
file_path = Path(file_path)
|
|
92
|
+
|
|
93
|
+
with zipfile.ZipFile(file_path) as zip_file:
|
|
94
|
+
_extract_zip(zip_file, "overrides/")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def apply_server_overrides(file_path: str | Path) -> None:
|
|
98
|
+
file_path = Path(file_path)
|
|
99
|
+
|
|
100
|
+
with zipfile.ZipFile(file_path) as zip_file:
|
|
101
|
+
_extract_zip(zip_file, "server-overrides/")
|
|
File without changes
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Imports
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
import logging as log
|
|
5
|
+
from typing import TypedDict
|
|
6
|
+
|
|
7
|
+
# MCServer
|
|
8
|
+
from .shared import project_records_dir
|
|
9
|
+
from .shared import DependencyTypes
|
|
10
|
+
|
|
11
|
+
# Types
|
|
12
|
+
dependency_types: list[str] = ["embedded", "optional", "required", "incompatible"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# TypedDicts
|
|
16
|
+
class ProjectRelationships(TypedDict):
|
|
17
|
+
dependencies: dict[str, DependencyTypes]
|
|
18
|
+
dependents: dict[str, DependencyTypes]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Functions
|
|
22
|
+
def create(
|
|
23
|
+
project_id: str,
|
|
24
|
+
dependencies: dict[str, DependencyTypes] | None = None,
|
|
25
|
+
dependents: dict[str, DependencyTypes] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Create a new project relationships record
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
project_id: The Modrinth project ID
|
|
31
|
+
dependencies: List of dependencies and its type
|
|
32
|
+
dependents: List of dependents and its type
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
FileNotFoundError: When project_records_dir does not exist
|
|
36
|
+
FileExistError: When project already have a record
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
None
|
|
40
|
+
"""
|
|
41
|
+
if dependencies is None:
|
|
42
|
+
dependencies = {}
|
|
43
|
+
|
|
44
|
+
if dependents is None:
|
|
45
|
+
dependents = {}
|
|
46
|
+
|
|
47
|
+
if not project_records_dir.exists():
|
|
48
|
+
raise FileNotFoundError(f"Directory '{project_records_dir}' does not exist")
|
|
49
|
+
|
|
50
|
+
project_record_dir = project_records_dir / project_id
|
|
51
|
+
relationships_file = project_record_dir / "relationships.json"
|
|
52
|
+
if relationships_file.exists():
|
|
53
|
+
raise FileExistsError(
|
|
54
|
+
f"Relationships for project ID '{project_id}' already exists"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
project_relationships: ProjectRelationships = {"dependencies": {}, "dependents": {}}
|
|
58
|
+
for dependency_id, dependency_type in dependencies.items():
|
|
59
|
+
if dependency_type not in dependency_types:
|
|
60
|
+
log.error(
|
|
61
|
+
f"Invalid dependency type '{dependency_type}' for dependency ID '{dependency_id}' of project ID '{project_id}', ignoring..."
|
|
62
|
+
)
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
project_relationships["dependencies"][dependency_id] = dependency_type
|
|
66
|
+
|
|
67
|
+
for dependent_id, dependency_type in dependents.items():
|
|
68
|
+
if dependency_type not in dependency_types:
|
|
69
|
+
log.error(
|
|
70
|
+
f"Invalid dependency type '{dependency_type}' for dependent ID '{dependent_id}' of project ID '{project_id}', ignoring..."
|
|
71
|
+
)
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
project_relationships["dependents"][dependent_id] = dependency_type
|
|
75
|
+
|
|
76
|
+
relationships_data = json.dumps(project_relationships, indent=2)
|
|
77
|
+
relationships_file.write_text(relationships_data)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def read(project_id: str) -> ProjectRelationships:
|
|
81
|
+
"""Read a project's relationships record
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
project_id: The Modrinth project ID
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
FileNotFoundError: Project has no relationships record or project_records_dir does not exist
|
|
88
|
+
json.JSONDecodeError: Project relationships record file is corrupted
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of dependencies and dependents of the project
|
|
92
|
+
"""
|
|
93
|
+
if not project_records_dir.exists():
|
|
94
|
+
raise FileNotFoundError(f"Directory '{project_records_dir}' does not exist")
|
|
95
|
+
|
|
96
|
+
project_record_dir = project_records_dir / project_id
|
|
97
|
+
relationships_file = project_record_dir / "relationships.json"
|
|
98
|
+
project_relationships: ProjectRelationships = {"dependencies": {}, "dependents": {}}
|
|
99
|
+
|
|
100
|
+
if not relationships_file.exists():
|
|
101
|
+
raise FileNotFoundError(
|
|
102
|
+
f"Relationships file for project ID '{project_id}' does not exist"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
relationships_data = relationships_file.read_text()
|
|
106
|
+
relationships_json: ProjectRelationships = {"dependencies": {}, "dependents": {}}
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
relationships_json = json.loads(relationships_data)
|
|
110
|
+
except json.JSONDecodeError as error:
|
|
111
|
+
raise error
|
|
112
|
+
|
|
113
|
+
dependencies = relationships_json["dependencies"]
|
|
114
|
+
dependents = relationships_json["dependents"]
|
|
115
|
+
|
|
116
|
+
for dependency_id, dependency_type in dependencies.items():
|
|
117
|
+
if dependency_type not in dependency_types:
|
|
118
|
+
log.error(
|
|
119
|
+
f"Invalid type '{dependency_type}' for dependency ID '{dependency_id}' of project ID '{project_id}', ignoring..."
|
|
120
|
+
)
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
project_relationships["dependencies"][dependency_id] = dependency_type
|
|
124
|
+
|
|
125
|
+
for dependent_id, dependent_type in dependents.items():
|
|
126
|
+
if dependent_type not in dependency_types:
|
|
127
|
+
log.error(
|
|
128
|
+
f"Invalid type '{dependent_type}' for dependent ID '{dependent_id}' of project ID '{project_id}', ignoring..."
|
|
129
|
+
)
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
project_relationships["dependents"][dependent_id] = dependent_type
|
|
133
|
+
|
|
134
|
+
return project_relationships
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def update(
|
|
138
|
+
project_id: str,
|
|
139
|
+
new_dependencies: dict[str, DependencyTypes] | None = None,
|
|
140
|
+
new_dependents: dict[str, DependencyTypes] | None = None,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Update an existing project relationships record
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
project_id: The Modrinth project ID
|
|
146
|
+
new_dependencies: New dependencies relationships data
|
|
147
|
+
new_dependents: New dependents relationships data
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
FileNotFoundError: Project has no relationships record or project_records_dir does not exist
|
|
151
|
+
json.JSONDecodeError: Project relationships record file is corrupted
|
|
152
|
+
"""
|
|
153
|
+
if new_dependencies is None:
|
|
154
|
+
new_dependencies = {}
|
|
155
|
+
|
|
156
|
+
if new_dependents is None:
|
|
157
|
+
new_dependents = {}
|
|
158
|
+
|
|
159
|
+
if not project_records_dir.exists():
|
|
160
|
+
raise FileNotFoundError(f"Directory '{project_records_dir}' does not exist")
|
|
161
|
+
|
|
162
|
+
project_record_dir = project_records_dir / project_id
|
|
163
|
+
relationships_file = project_record_dir / "relationships.json"
|
|
164
|
+
if not relationships_file.exists():
|
|
165
|
+
raise FileNotFoundError(
|
|
166
|
+
f"Relationships file for project ID '{project_id}' does not exist"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
project_relationships: ProjectRelationships = {"dependencies": {}, "dependents": {}}
|
|
170
|
+
relationships_data = relationships_file.read_text()
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
relationships_json = json.loads(relationships_data)
|
|
174
|
+
except json.JSONDecodeError as error:
|
|
175
|
+
raise error
|
|
176
|
+
|
|
177
|
+
project_relationships.update(relationships_json)
|
|
178
|
+
relationships_data = json.dumps(project_relationships, indent=2)
|
|
179
|
+
relationships_file.write_text(relationships_data)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def delete(project_id: str):
|
|
183
|
+
""" "Delete a project's relationships record
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
project_id: The Modrinth project ID
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
FileNotFoundError: Project has no relationships record or project_records_dir does not exist
|
|
190
|
+
"""
|
|
191
|
+
if not project_records_dir.exists():
|
|
192
|
+
raise FileNotFoundError(
|
|
193
|
+
f"Relationships file for project ID '{project_id}' does not exist"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
project_record_dir = project_records_dir / project_id
|
|
197
|
+
relationships_file = project_record_dir / "relationships.json"
|
|
198
|
+
if not relationships_file.exists():
|
|
199
|
+
raise FileNotFoundError(
|
|
200
|
+
f"Relationships file for project ID '{project_id}' does not exist"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
relationships_file.unlink()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from ..shared import merge_dict
|
|
6
|
+
|
|
7
|
+
# MCServer
|
|
8
|
+
from .shared import modrinth_dir
|
|
9
|
+
|
|
10
|
+
# Paths
|
|
11
|
+
projects_dir = modrinth_dir / "projects"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Functions
|
|
15
|
+
def create_project_entry(
|
|
16
|
+
project_id: str, metadata: dict | None = None, relationship: dict | None = None
|
|
17
|
+
) -> None:
|
|
18
|
+
if metadata is None:
|
|
19
|
+
metadata = {}
|
|
20
|
+
if relationship is None:
|
|
21
|
+
relationship = {}
|
|
22
|
+
|
|
23
|
+
project_entry = projects_dir / project_id
|
|
24
|
+
project_metadata = project_entry / "metadata.json"
|
|
25
|
+
project_relationship = project_entry / "relationship.json"
|
|
26
|
+
|
|
27
|
+
if project_entry.exists():
|
|
28
|
+
raise FileExistsError(f"Project index for '{project_id}' already exists")
|
|
29
|
+
|
|
30
|
+
project_entry.mkdir(parents=True)
|
|
31
|
+
project_metadata.write_text(json.dumps(metadata, indent=2))
|
|
32
|
+
project_relationship.write_text(json.dumps(relationship, indent=2))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def read_project_entry(project_id: str) -> dict:
|
|
36
|
+
project_index = projects_dir / project_id
|
|
37
|
+
project_metadata = project_index / "metadata.json"
|
|
38
|
+
project_relationship = project_index / "relationship.json"
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
"metadata": json.loads(project_metadata.read_text()),
|
|
42
|
+
"relationship": json.loads(project_relationship.read_text()),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def update_project_entry(
|
|
47
|
+
project_id: str,
|
|
48
|
+
new_metadata: dict | None = None,
|
|
49
|
+
new_relationship: dict | None = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
if new_metadata is None:
|
|
52
|
+
new_metadata = {}
|
|
53
|
+
if new_relationship is None:
|
|
54
|
+
new_relationship = {}
|
|
55
|
+
|
|
56
|
+
project_index = projects_dir / project_id
|
|
57
|
+
project_metadata = project_index / "metadata.json"
|
|
58
|
+
project_relationship = project_index / "relationship.json"
|
|
59
|
+
|
|
60
|
+
old_data = read_project_entry(project_id)
|
|
61
|
+
project_metadata.write_text(
|
|
62
|
+
json.dumps(merge_dict(old_data["metadata"], new_metadata), indent=2)
|
|
63
|
+
)
|
|
64
|
+
project_relationship.write_text(
|
|
65
|
+
json.dumps(merge_dict(old_data["relationship"], new_relationship), indent=2)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def delete_project_entry(project_id: str) -> None:
|
|
70
|
+
project_index = projects_dir / project_id
|
|
71
|
+
project_metadata = project_index / "metadata.json"
|
|
72
|
+
project_relationship = project_index / "relationship.json"
|
|
73
|
+
|
|
74
|
+
project_metadata.unlink()
|
|
75
|
+
project_relationship.unlink()
|
|
76
|
+
project_index.rmdir()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def project_entry_exists(project_id: str) -> bool:
|
|
80
|
+
return (projects_dir / project_id).exists()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Literal, TypeAlias
|
|
5
|
+
|
|
6
|
+
# MCServer
|
|
7
|
+
from ..shared import mcserver_dir
|
|
8
|
+
|
|
9
|
+
# TypeAliases
|
|
10
|
+
DependencyTypes: TypeAlias = Literal["embedded", "optional", "required", "incompatible"]
|
|
11
|
+
|
|
12
|
+
# Variables
|
|
13
|
+
modrinth_dir: Path = mcserver_dir / "modrinth"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
# MCServer
|
|
6
|
+
from .shared import modrinth_dir
|
|
7
|
+
|
|
8
|
+
# Variables
|
|
9
|
+
_slug_index = None
|
|
10
|
+
|
|
11
|
+
# Paths
|
|
12
|
+
slug_index_file = modrinth_dir / "slug_index.json"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Functions
|
|
16
|
+
def _load_slug_index() -> None:
|
|
17
|
+
global _slug_index
|
|
18
|
+
if _slug_index is None:
|
|
19
|
+
_slug_index = json.loads(slug_index_file.read_text())
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def slug_to_id(project_slug: str) -> str:
|
|
23
|
+
_load_slug_index()
|
|
24
|
+
project_id: str = ""
|
|
25
|
+
if _slug_index is not None:
|
|
26
|
+
project_id = _slug_index.get(project_slug, project_slug)["id"]
|
|
27
|
+
|
|
28
|
+
return project_id
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def add_slug(project_slug: str, project_id: str) -> None:
|
|
32
|
+
global _slug_index
|
|
33
|
+
if _slug_index is None:
|
|
34
|
+
_slug_index = {}
|
|
35
|
+
|
|
36
|
+
_slug_index[project_slug] = project_id
|
mcserver/mojang/eula.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
import time
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
# Paths
|
|
7
|
+
eula_file = Path("eula.txt")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Functions
|
|
11
|
+
def is_eula_agreed() -> bool:
|
|
12
|
+
try:
|
|
13
|
+
for line in eula_file.read_text().split("\n"):
|
|
14
|
+
if line.startswith("eula=true"):
|
|
15
|
+
return True
|
|
16
|
+
except FileNotFoundError:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def eula_agree() -> None:
|
|
23
|
+
timestamp = time.strftime("%a %b %d %H:%M:%S GMT %Y", time.gmtime())
|
|
24
|
+
eula_file.write_text(
|
|
25
|
+
f"""#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA).
|
|
26
|
+
#{timestamp}
|
|
27
|
+
eula=true"""
|
|
28
|
+
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
# Standard
|
|
3
|
+
import json
|
|
4
|
+
from typing import TypedDict
|
|
5
|
+
|
|
6
|
+
# MCServer
|
|
7
|
+
from .. import networking
|
|
8
|
+
from ..constants import mojang_manifest_url
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# TypedDict
|
|
12
|
+
class LatestVersion(TypedDict):
|
|
13
|
+
release_version: str # original: release
|
|
14
|
+
snapshot_version: str # original: snapshot
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GameVersion(TypedDict):
|
|
18
|
+
version_id: str # original: id
|
|
19
|
+
version_type: str # original: type
|
|
20
|
+
package_url: str # original: url
|
|
21
|
+
release_time: str # original: releaseTime
|
|
22
|
+
package_sha1: str # original: sha1
|
|
23
|
+
compliance_level: int # original: complianceLevel
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class VersionManifest(TypedDict):
|
|
27
|
+
latest_game_version: LatestVersion # original: latest
|
|
28
|
+
game_versions: list[GameVersion] # original: versions
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Functions
|
|
32
|
+
def get_version_manifest() -> VersionManifest:
|
|
33
|
+
response = networking.request(
|
|
34
|
+
f"{mojang_manifest_url}/mc/game/version_manifest_v2.json"
|
|
35
|
+
)
|
|
36
|
+
response_json = json.loads(response["text"])
|
|
37
|
+
|
|
38
|
+
latest_version = response_json["latest"]
|
|
39
|
+
|
|
40
|
+
game_versions: list[GameVersion] = []
|
|
41
|
+
for version in response_json["versions"]:
|
|
42
|
+
game_version: GameVersion = {
|
|
43
|
+
"version_id": version["id"],
|
|
44
|
+
"version_type": version["type"],
|
|
45
|
+
"release_time": version["releaseTime"],
|
|
46
|
+
"package_url": version["url"],
|
|
47
|
+
"package_sha1": version["sha1"],
|
|
48
|
+
"compliance_level": version["complianceLevel"],
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
game_versions.append(game_version)
|
|
52
|
+
|
|
53
|
+
version_manifest: VersionManifest = {
|
|
54
|
+
"latest_game_version": {
|
|
55
|
+
"release_version": latest_version["release"],
|
|
56
|
+
"snapshot_version": latest_version["snapshot"],
|
|
57
|
+
},
|
|
58
|
+
"game_versions": game_versions,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return version_manifest
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_latest_release_version() -> str:
|
|
65
|
+
return get_version_manifest()["latest_game_version"]["release_version"]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_latest_snapshot_version() -> str:
|
|
69
|
+
return get_version_manifest()["latest_game_version"]["snapshot_version"]
|