mcmu 1.4.0.dev0__tar.gz → 2.0.0.dev1__tar.gz
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.
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/CHANGELOG.md +14 -24
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/PKG-INFO +6 -3
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/README.md +4 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/TODO.md +1 -2
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/pyproject.toml +1 -2
- mcmu-2.0.0.dev1/src/mcmu/Mod.py +24 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/src/mcmu/ModrinthAPI.py +1 -2
- mcmu-2.0.0.dev1/src/mcmu/UPGRADING.md +9 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/src/mcmu/__main__.py +17 -58
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/.github/ISSUE_TEMPLATE/custom.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/.github/pull_request_template.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/.gitignore +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/CODE_OF_CONDUCT.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/CONTRIBUTING.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/LICENSE +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/Makefile +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/SECURITY.md +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/requirements.txt +0 -0
- {mcmu-1.4.0.dev0 → mcmu-2.0.0.dev1}/src/mcmu/__init__.py +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## **2.0.0.dev1** - 2026-03-17
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
* Changed the name of the file when downloading
|
|
8
|
+
|
|
9
|
+
### Removed
|
|
10
|
+
|
|
11
|
+
* Removed the need for the config file
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
* Fixed displaying mod name when upgrading
|
|
16
|
+
|
|
3
17
|
## [1.4.0.dev0] - 2026-03-16
|
|
4
18
|
|
|
5
19
|
### Added
|
|
@@ -237,27 +251,3 @@ This is the first release candidate for version [1.0.0+1.21.11].
|
|
|
237
251
|
## [0.1.0] - 2026-03-03
|
|
238
252
|
|
|
239
253
|
- Initial Release
|
|
240
|
-
|
|
241
|
-
[0.1.0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.1.0
|
|
242
|
-
[0.1.1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.1.1
|
|
243
|
-
[0.1.2]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.1.2
|
|
244
|
-
[0.1.3]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.1.3
|
|
245
|
-
[0.1.4]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.1.4
|
|
246
|
-
[0.2.0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.2.0
|
|
247
|
-
[0.2.1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.2.1
|
|
248
|
-
[0.2.2]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/0.2.2
|
|
249
|
-
[1.0.0rc0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.0.0rc0
|
|
250
|
-
[1.0.0rc1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.0.0rc1
|
|
251
|
-
[1.0.0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.0.0
|
|
252
|
-
[1.1.0.dev0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.1.0.dev0
|
|
253
|
-
[1.1.0.dev1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.1.0.dev1
|
|
254
|
-
[1.1.0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.1.0
|
|
255
|
-
[1.1.1a0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.1.1a0
|
|
256
|
-
[1.1.1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.1.1
|
|
257
|
-
[1.2.0.dev0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0.dev0
|
|
258
|
-
[1.2.0.dev1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0.dev1
|
|
259
|
-
[1.2.0a0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0a0
|
|
260
|
-
[1.2.0a1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0a1
|
|
261
|
-
[1.2.0rc0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0rc0
|
|
262
|
-
[1.2.0]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.0
|
|
263
|
-
[1.2.1]: https://github.com/Josiah-Jarvis/MCModUpdater/releases/tag/1.2.1
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcmu
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0.dev1
|
|
4
4
|
Summary: A utility to update Minecraft java edition mods from Modrinth
|
|
5
5
|
Project-URL: homepage, https://github.com/Josiah-Jarvis/MCMU
|
|
6
6
|
Project-URL: source, https://github.com/Josiah-Jarvis/MCMU/
|
|
7
7
|
Project-URL: download, https://pypi.org/project/mcmu/#files
|
|
8
8
|
Project-URL: changelog, https://github.com/Josiah-Jarvis/MCMU/blob/master/CHANGELOG.md
|
|
9
|
-
Project-URL: releasenotes, https://github.com/Josiah-Jarvis/MCMU/compare/v1.
|
|
9
|
+
Project-URL: releasenotes, https://github.com/Josiah-Jarvis/MCMU/compare/v1.4.0.dev0...v2.0.0.dev1
|
|
10
10
|
Project-URL: documentation, https://github.com/Josiah-Jarvis/MCMU/blob/master/README.md
|
|
11
11
|
Project-URL: issues, https://github.com/Josiah-Jarvis/MCMU/issues
|
|
12
12
|
Author: Josiah Jarvis
|
|
@@ -25,7 +25,6 @@ Classifier: Natural Language :: English
|
|
|
25
25
|
Classifier: Operating System :: MacOS
|
|
26
26
|
Classifier: Operating System :: Microsoft
|
|
27
27
|
Classifier: Operating System :: Microsoft :: Windows
|
|
28
|
-
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
29
28
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
30
29
|
Classifier: Operating System :: POSIX
|
|
31
30
|
Classifier: Operating System :: POSIX :: Linux
|
|
@@ -126,3 +125,7 @@ mcmu -g game_version -i mod-name
|
|
|
126
125
|
### How does it work?
|
|
127
126
|
|
|
128
127
|
It works a lot like a package manager actually! It pulls the mods from a source (Modrinth) and installs them on the system. It keeps a list of the installed mods in a config file for easy access of the installed mods.
|
|
128
|
+
|
|
129
|
+
### What happened to v1.4.0?
|
|
130
|
+
|
|
131
|
+
It turned into v2.0.0.
|
|
@@ -82,3 +82,7 @@ mcmu -g game_version -i mod-name
|
|
|
82
82
|
### How does it work?
|
|
83
83
|
|
|
84
84
|
It works a lot like a package manager actually! It pulls the mods from a source (Modrinth) and installs them on the system. It keeps a list of the installed mods in a config file for easy access of the installed mods.
|
|
85
|
+
|
|
86
|
+
### What happened to v1.4.0?
|
|
87
|
+
|
|
88
|
+
It turned into v2.0.0.
|
|
@@ -28,7 +28,6 @@ classifiers = [
|
|
|
28
28
|
"Operating System :: MacOS",
|
|
29
29
|
"Operating System :: Microsoft",
|
|
30
30
|
"Operating System :: Microsoft :: Windows",
|
|
31
|
-
"Operating System :: Microsoft :: Windows :: Windows 10",
|
|
32
31
|
"Operating System :: Microsoft :: Windows :: Windows 11",
|
|
33
32
|
"Operating System :: POSIX",
|
|
34
33
|
"Operating System :: POSIX :: Linux",
|
|
@@ -52,7 +51,7 @@ homepage = "https://github.com/Josiah-Jarvis/MCMU"
|
|
|
52
51
|
source = "https://github.com/Josiah-Jarvis/MCMU/"
|
|
53
52
|
download = "https://pypi.org/project/mcmu/#files"
|
|
54
53
|
changelog = "https://github.com/Josiah-Jarvis/MCMU/blob/master/CHANGELOG.md"
|
|
55
|
-
releasenotes = "https://github.com/Josiah-Jarvis/MCMU/compare/v1.
|
|
54
|
+
releasenotes = "https://github.com/Josiah-Jarvis/MCMU/compare/v1.4.0.dev0...v2.0.0.dev1" # Change before every release
|
|
56
55
|
documentation = "https://github.com/Josiah-Jarvis/MCMU/blob/master/README.md"
|
|
57
56
|
issues = "https://github.com/Josiah-Jarvis/MCMU/issues"
|
|
58
57
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from re import match
|
|
5
|
+
from os import listdir
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Mod:
|
|
10
|
+
def __init__(self, mod_path: Path):
|
|
11
|
+
self.mod_path = mod_path
|
|
12
|
+
|
|
13
|
+
def list_mods(self):
|
|
14
|
+
mods = {}
|
|
15
|
+
for mod in listdir(self.mod_path):
|
|
16
|
+
pattern = r'^(.*?)_version_(.*)\.jar$'
|
|
17
|
+
m = match(pattern, mod)
|
|
18
|
+
mods[m.group(1)] = {
|
|
19
|
+
"name": m.group(1),
|
|
20
|
+
"version": m.group(2),
|
|
21
|
+
"file": mod
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return mods
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Breaking changes between v1.3.0 and v2.0.0
|
|
2
|
+
|
|
3
|
+
This update breaks everything!
|
|
4
|
+
|
|
5
|
+
Why does it break everything? Because we are dropping the config file! Now the config is stored in the mods file name, now it is stored as {mod_name}_version_{mod_version}.jar.
|
|
6
|
+
|
|
7
|
+
## How to update safely
|
|
8
|
+
|
|
9
|
+
In v1.3.0 of MCMU do `mcmu -l` to get a list of all your mods. Keep this safe. One by one delete all your mods with `mcmu -r <modname>` then update MCMU with `pip install --upgrade mcmu`. Next reinstall all your mods with `mcmu -i <modname>`.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
from json import load, dump, JSONDecodeError # Import JSON functions
|
|
4
|
+
import sys
|
|
6
5
|
from pathlib import Path # Import for file functions
|
|
7
6
|
from logging import getLogger, basicConfig # Logging functionality
|
|
8
7
|
from requests import get # Get files from the CDN
|
|
9
8
|
from argparse import ArgumentParser # Command line arguments class
|
|
10
9
|
from .ModrinthAPI import ModrinthAPI # Modrinth API code (Local import)
|
|
10
|
+
from .Mod import Mod
|
|
11
11
|
|
|
12
|
-
__version__ = "
|
|
12
|
+
__version__ = "2.0.0.dev1"
|
|
13
13
|
__author__ = "Josiah Jarvis"
|
|
14
14
|
|
|
15
15
|
logger = getLogger(__name__)
|
|
@@ -33,6 +33,7 @@ config_file = Path(args.minecraft_dir, "config/mcmu.json") # Path to the config
|
|
|
33
33
|
|
|
34
34
|
ModAPI = ModrinthAPI(f"Josiah-Jarvis/MCMU/{__version__} (https://github.com/Josiah-Jarvis/MCMU)")
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
def check_update(mod_name: str, current_version: str) -> [bool, dict]:
|
|
37
38
|
"""Checks for mod update from Modrinth
|
|
38
39
|
|
|
@@ -61,24 +62,6 @@ def check_update(mod_name: str, current_version: str) -> [bool, dict]:
|
|
|
61
62
|
return latest_version
|
|
62
63
|
return False # Return false for failure
|
|
63
64
|
|
|
64
|
-
def write_config_file(config_f: Path, config_d: dict):
|
|
65
|
-
"""Writes the config file
|
|
66
|
-
|
|
67
|
-
Arguments:
|
|
68
|
-
config_f -- The config file
|
|
69
|
-
config_d -- The config data
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
True: Success
|
|
73
|
-
False: Failure
|
|
74
|
-
"""
|
|
75
|
-
try:
|
|
76
|
-
with open(config_f, "w") as fp: # Open the config file
|
|
77
|
-
dump(config_d, fp, indent=4) # Write the config file
|
|
78
|
-
return True
|
|
79
|
-
except PermissionError: # Uh oh we do not have permission
|
|
80
|
-
logger.error("No permission to write to file.")
|
|
81
|
-
return False
|
|
82
65
|
|
|
83
66
|
def main():
|
|
84
67
|
"""Main function
|
|
@@ -87,23 +70,8 @@ def main():
|
|
|
87
70
|
1: Failure
|
|
88
71
|
0: Success
|
|
89
72
|
"""
|
|
90
|
-
try:
|
|
91
|
-
with open(config_file, "r") as fp: # Open the config file
|
|
92
|
-
config = load(fp) # Read the config file
|
|
93
|
-
except JSONDecodeError:
|
|
94
|
-
logger.critical("Config file not valid JSON.") # Well its not valid JSON
|
|
95
|
-
return 1
|
|
96
|
-
except FileNotFoundError: # Oops config file does not exist
|
|
97
|
-
logger.warn("Config file does not exist.")
|
|
98
|
-
with open(config_file, "w") as fp: # Create the file since it does not exist
|
|
99
|
-
logger.debug("Creating config file.")
|
|
100
|
-
dump({"mods":{}}, fp, indent=4)
|
|
101
|
-
config = {"mods":{}}
|
|
102
|
-
except PermissionError: # Can't we just have the permission :?
|
|
103
|
-
logger.error("No permission to write to file.")
|
|
104
|
-
return 1
|
|
105
|
-
mods = copy(config['mods']) # Get the mods data from the config file
|
|
106
73
|
mod_path = Path(args.minecraft_dir, "mods/") # Path to folder where the mod jar's are stored
|
|
74
|
+
mods = Mod(mod_path).list_mods()
|
|
107
75
|
if not mod_path.exists():
|
|
108
76
|
logger.critical(f"Mods folder: {mod_path} does not exist. Please create it.\nExiting...") # Fabric creates the mods/ folder on first run by they might not have run it yet
|
|
109
77
|
return 1
|
|
@@ -119,27 +87,24 @@ def main():
|
|
|
119
87
|
elif latest_version: # If latest version is a dict it should return True
|
|
120
88
|
old_file = Path(mod_path, mods[mod_name]['file']) # Path to the old mod file
|
|
121
89
|
additional_storage = latest_version['files'][0]['size'] - old_file.stat().st_size # Calculate how much more storage will be taken up
|
|
122
|
-
if input(f"{
|
|
90
|
+
if input(f"{mods[mod_name]['name']} will take up: {additional_storage} additional bytes, would you like to install? [Y/n]: ") is ("" or "Y"): # Ask them if they want to install it
|
|
123
91
|
old_file.unlink() # Delete old file
|
|
124
92
|
response = get(latest_version['files'][0]['url'], stream=True) # Get the new file
|
|
125
93
|
if response.status_code != 200: # If its not 200 fail
|
|
126
94
|
print(f"Failed to download the mod. Status code: {response.status_code}")
|
|
127
95
|
return 1
|
|
128
|
-
with open(f"{mod_path}/{latest_version['
|
|
96
|
+
with open(f"{mod_path}/{args.install}_version_{latest_version['version_number']}.jar", 'wb') as file: # IF everything good write to the file
|
|
129
97
|
for chunk in response.iter_content(chunk_size=1024):
|
|
130
98
|
if chunk:
|
|
131
99
|
file.write(chunk)
|
|
132
|
-
print(f"Downloaded {latest_version['
|
|
133
|
-
config['mods'][mod_name] = {'file': latest_version['files'][0]['filename'], 'version': latest_version['version_number'], 'name': mod_name}
|
|
134
|
-
if not write_config_file(config_file, config): # Write the config file
|
|
135
|
-
return 1 # Fail if writing failed
|
|
100
|
+
print(f"Downloaded mod at {mod_path}/{args.install}_version_{latest_version['version_number']}.jar successfully.") # Print the success
|
|
136
101
|
else:
|
|
137
102
|
print("Canceling.")
|
|
138
103
|
return 0
|
|
139
104
|
else:
|
|
140
105
|
print(f"Mod: {mod_name} at latest version!")
|
|
141
106
|
elif args.install: # If were installing the mod
|
|
142
|
-
if args.install in
|
|
107
|
+
if args.install in mods: # If mod already installed exit
|
|
143
108
|
print(f"{args.install} already installed.")
|
|
144
109
|
return 0
|
|
145
110
|
latest_version = check_update(args.install, "0") # Set the version to 0 so any version would be higher
|
|
@@ -152,14 +117,11 @@ def main():
|
|
|
152
117
|
if response.status_code != 200:
|
|
153
118
|
print(f"Failed to download the mod. Status code: {response.status_code}")
|
|
154
119
|
return False
|
|
155
|
-
with open(f"{mod_path}/{latest_version['
|
|
120
|
+
with open(f"{mod_path}/{args.install}_version_{latest_version['version_number']}.jar", 'wb') as file: # Write to the jar file
|
|
156
121
|
for chunk in response.iter_content(chunk_size=1024):
|
|
157
122
|
if chunk:
|
|
158
123
|
file.write(chunk)
|
|
159
|
-
print(f"Downloaded {latest_version['
|
|
160
|
-
config['mods'][args.install] = {'file': latest_version['files'][0]['filename'], 'version': latest_version['version_number'], 'name': args.install}
|
|
161
|
-
if not write_config_file(config_file, config): # Write to the config file
|
|
162
|
-
return 1
|
|
124
|
+
print(f"Downloaded mod at {mod_path}/{args.install}_version_{latest_version['version_number']}.jar successfully.") # Print the success
|
|
163
125
|
else:
|
|
164
126
|
print("Canceling.")
|
|
165
127
|
return 0
|
|
@@ -167,11 +129,11 @@ def main():
|
|
|
167
129
|
logger.error("Mod does not exist on Modrinth")
|
|
168
130
|
return 1
|
|
169
131
|
elif args.remove: # If were removing the mod
|
|
170
|
-
if args.remove not in
|
|
132
|
+
if args.remove not in mods: # If the mod is not listed in the config file exit with error
|
|
171
133
|
logger.error("Mod not installed")
|
|
172
134
|
return 1
|
|
173
135
|
try:
|
|
174
|
-
mod_file = Path(mod_path,
|
|
136
|
+
mod_file = Path(mod_path, mods[args.remove]['file']) # Path to the mod jar
|
|
175
137
|
if input(f"Would you like to remove {args.remove}? This operation will clear {mod_file.stat().st_size} bytes. [Y/n]: ") is ("" or "Y"): # Ask if they want to remove it
|
|
176
138
|
mod_file.unlink() # Remove the file
|
|
177
139
|
else:
|
|
@@ -182,24 +144,21 @@ def main():
|
|
|
182
144
|
except PermissionError: # No permission to delete the file
|
|
183
145
|
logger.critical("No permission to delete mod file.")
|
|
184
146
|
return 1
|
|
185
|
-
del config['mods'][args.remove] # Remove the mods entry in the config file
|
|
186
|
-
if not write_config_file(config_file, config): # Write to the config file
|
|
187
|
-
return 1
|
|
188
147
|
print(f"Mod: {args.remove}, successfully removed") # Print success
|
|
189
148
|
return 0
|
|
190
149
|
elif args.list: # List installed mod
|
|
191
|
-
for mod in
|
|
192
|
-
print(f"{
|
|
150
|
+
for mod in mods: # Iterate over all installed mods
|
|
151
|
+
print(f"{mods[mod]['name']}\n\tVersion: {mods[mod]['version']}\n\tFile: {mods[mod]['file']}")
|
|
193
152
|
elif args.search: # If we are searching for a mod
|
|
194
153
|
response = ModAPI.search(args.search, '[["categories:fabric"],["project_type:mod"]]')
|
|
195
154
|
if response == 410: # That means the API is deprecated: https://docs.modrinth.com/api/
|
|
196
155
|
logger.critical("API is deprecated, you probably have to update MCMU")
|
|
197
156
|
elif response == 400: # Response of 400 means request was invalid: https://docs.modrinth.com/api/operations/searchprojects/
|
|
198
|
-
logger.error(
|
|
157
|
+
logger.error("Request invalid") # Print error
|
|
199
158
|
else:
|
|
200
159
|
for mod in response['hits']: # Iterate over and list all the mods
|
|
201
160
|
print(f"{mod['title']}:\n\tDescription: {mod['description']}\n\tAuthor: {mod['author']}\n\tDownloads: {mod['downloads']}\n\tLatest Version: {mod['latest_version']}\n\n")
|
|
202
161
|
else:
|
|
203
162
|
parser.print_help() # Prints help message if there is nothing to do
|
|
204
163
|
|
|
205
|
-
return 0
|
|
164
|
+
return 0 # Return 0 if all good
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|