zucaro 0.5.1__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.
Files changed (45) hide show
  1. zucaro-0.5.1/.git-blame-ignore-revs +2 -0
  2. zucaro-0.5.1/.github/workflows/pypi.yml +57 -0
  3. zucaro-0.5.1/.gitignore +10 -0
  4. zucaro-0.5.1/LICENSE +22 -0
  5. zucaro-0.5.1/PKG-INFO +59 -0
  6. zucaro-0.5.1/README.md +44 -0
  7. zucaro-0.5.1/pyproject.toml +37 -0
  8. zucaro-0.5.1/requirements-dev.lock +30 -0
  9. zucaro-0.5.1/requirements.lock +30 -0
  10. zucaro-0.5.1/src/zucaro/__init__.py +16 -0
  11. zucaro-0.5.1/src/zucaro/__main__.py +6 -0
  12. zucaro-0.5.1/src/zucaro/account.py +232 -0
  13. zucaro-0.5.1/src/zucaro/cli/__init__.py +14 -0
  14. zucaro-0.5.1/src/zucaro/cli/account.py +127 -0
  15. zucaro-0.5.1/src/zucaro/cli/config.py +56 -0
  16. zucaro-0.5.1/src/zucaro/cli/instance.py +200 -0
  17. zucaro-0.5.1/src/zucaro/cli/main.py +62 -0
  18. zucaro-0.5.1/src/zucaro/cli/mod.py +57 -0
  19. zucaro-0.5.1/src/zucaro/cli/play.py +68 -0
  20. zucaro-0.5.1/src/zucaro/cli/utils.py +40 -0
  21. zucaro-0.5.1/src/zucaro/cli/version.py +85 -0
  22. zucaro-0.5.1/src/zucaro/config.py +135 -0
  23. zucaro-0.5.1/src/zucaro/downloader.py +163 -0
  24. zucaro-0.5.1/src/zucaro/errors.py +28 -0
  25. zucaro-0.5.1/src/zucaro/instance.py +281 -0
  26. zucaro-0.5.1/src/zucaro/java/SysDump.class +0 -0
  27. zucaro-0.5.1/src/zucaro/java/__init__.py +122 -0
  28. zucaro-0.5.1/src/zucaro/java_manager.py +166 -0
  29. zucaro-0.5.1/src/zucaro/launcher.py +116 -0
  30. zucaro-0.5.1/src/zucaro/library.py +159 -0
  31. zucaro-0.5.1/src/zucaro/logging.py +16 -0
  32. zucaro-0.5.1/src/zucaro/mod/__init__.py +4 -0
  33. zucaro-0.5.1/src/zucaro/mod/curse.py +257 -0
  34. zucaro-0.5.1/src/zucaro/mod/fabric.py +161 -0
  35. zucaro-0.5.1/src/zucaro/mod/forge.py +413 -0
  36. zucaro-0.5.1/src/zucaro/mod/ftb.py +159 -0
  37. zucaro-0.5.1/src/zucaro/mod/modrinth.py +278 -0
  38. zucaro-0.5.1/src/zucaro/mod/quilt.py +177 -0
  39. zucaro-0.5.1/src/zucaro/msapi.py +177 -0
  40. zucaro-0.5.1/src/zucaro/osinfo.py +39 -0
  41. zucaro-0.5.1/src/zucaro/rules.py +45 -0
  42. zucaro-0.5.1/src/zucaro/utils.py +63 -0
  43. zucaro-0.5.1/src/zucaro/version.py +422 -0
  44. zucaro-0.5.1/src/zucaro/windows.py +75 -0
  45. zucaro-0.5.1/src/zucaro/yggdrasil.py +75 -0
@@ -0,0 +1,2 @@
1
+ # change project strucutre
2
+ 16da1dc0d39f3390f2abeb6213a50ebb4124b77d
@@ -0,0 +1,57 @@
1
+ name: Try to upload Python Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ release-build:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.x"
21
+
22
+ - name: Python Setup Rye
23
+ uses: eifinger/setup-rye@v4.2.9
24
+ # optionally specify version:
25
+ # with:
26
+ # version: "0.44.0"
27
+
28
+ - name: Build release distributions with Rye
29
+ run: rye build
30
+
31
+ - name: Upload distributions
32
+ uses: actions/upload-artifact@v4
33
+ with:
34
+ name: release-dists
35
+ path: dist/
36
+
37
+ pypi-publish:
38
+ runs-on: ubuntu-latest
39
+ needs: release-build
40
+ permissions:
41
+ id-token: write
42
+
43
+ environment:
44
+ name: pypi
45
+ url: https://pypi.org/project/zucaro/${{ github.event.release.name }}
46
+
47
+ steps:
48
+ - name: Retrieve release distributions
49
+ uses: actions/download-artifact@v4
50
+ with:
51
+ name: release-dists
52
+ path: dist/
53
+
54
+ - name: Publish release distributions to PyPI
55
+ uses: pypa/gh-action-pypi-publish@release/v1
56
+ with:
57
+ packages-dir: dist/
@@ -0,0 +1,10 @@
1
+ # python generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # venv
10
+ .venv
zucaro-0.5.1/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2017-2024 Samuel Čavoj
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
zucaro-0.5.1/PKG-INFO ADDED
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: zucaro
3
+ Version: 0.5.1
4
+ Summary: A very small CLI Minecraft launcher.
5
+ Author-email: Samuel Čavoj <samuel@cavoj.net>
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.8
8
+ Requires-Dist: aiohttp==3.11.12
9
+ Requires-Dist: click~=8.1
10
+ Requires-Dist: colorama~=0.4
11
+ Requires-Dist: coloredlogs~=15.0
12
+ Requires-Dist: requests~=2.31
13
+ Requires-Dist: tqdm~=4.66
14
+ Description-Content-Type: text/markdown
15
+
16
+ # hey
17
+
18
+ This is a fork thats made to work as the backend of the picodulce launcher, this is a work in progress and a lot of things will change
19
+
20
+ this is a fork of the amazing work of [sammko](https://github.com/sammko/picomc)
21
+
22
+ zucaro
23
+ ====
24
+
25
+ `zucaro` is a cross-platform command-line Minecraft launcher. It supports
26
+ all(?) officialy available Minecraft versions, account switching and
27
+ multiple separate instances of the game. The on-disk launcher file
28
+ structure mimics the vanilla launcher and as such most mod installers
29
+ (such as forge, fabric or optifine) should work with zucaro just fine,
30
+ though you will have to change the installation path.
31
+ Don't hesitate to report any problems you run into.
32
+
33
+ Usage
34
+ ---
35
+
36
+ The quickest way to get started is to run
37
+
38
+ ```
39
+ zucaro play
40
+ ```
41
+
42
+ which, on the first launch, will ask you for your account details,
43
+ create an instance named `default` using the latest version of Minecraft
44
+ and launch it.
45
+
46
+ Of course, more advanced features are available. Try running
47
+
48
+ ```
49
+ zucaro --help
50
+ ```
51
+
52
+ and you should be able to figure it out. More detailed documentation
53
+ may appear someday in the future.
54
+
55
+ Development
56
+ ---
57
+
58
+ For project management and dependency tracking `zucaro` uses
59
+ [Rye](https://rye-up.com/).
zucaro-0.5.1/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # hey
2
+
3
+ This is a fork thats made to work as the backend of the picodulce launcher, this is a work in progress and a lot of things will change
4
+
5
+ this is a fork of the amazing work of [sammko](https://github.com/sammko/picomc)
6
+
7
+ zucaro
8
+ ====
9
+
10
+ `zucaro` is a cross-platform command-line Minecraft launcher. It supports
11
+ all(?) officialy available Minecraft versions, account switching and
12
+ multiple separate instances of the game. The on-disk launcher file
13
+ structure mimics the vanilla launcher and as such most mod installers
14
+ (such as forge, fabric or optifine) should work with zucaro just fine,
15
+ though you will have to change the installation path.
16
+ Don't hesitate to report any problems you run into.
17
+
18
+ Usage
19
+ ---
20
+
21
+ The quickest way to get started is to run
22
+
23
+ ```
24
+ zucaro play
25
+ ```
26
+
27
+ which, on the first launch, will ask you for your account details,
28
+ create an instance named `default` using the latest version of Minecraft
29
+ and launch it.
30
+
31
+ Of course, more advanced features are available. Try running
32
+
33
+ ```
34
+ zucaro --help
35
+ ```
36
+
37
+ and you should be able to figure it out. More detailed documentation
38
+ may appear someday in the future.
39
+
40
+ Development
41
+ ---
42
+
43
+ For project management and dependency tracking `zucaro` uses
44
+ [Rye](https://rye-up.com/).
@@ -0,0 +1,37 @@
1
+ [project]
2
+ name = "zucaro"
3
+ version = "0.5.1"
4
+ description = "A very small CLI Minecraft launcher."
5
+ authors = [
6
+ { name = "Samuel Čavoj", email = "samuel@cavoj.net" }
7
+ ]
8
+ dependencies = [
9
+ "click~=8.1",
10
+ "coloredlogs~=15.0",
11
+ "colorama~=0.4",
12
+ "requests~=2.31",
13
+ "tqdm~=4.66",
14
+ "aiohttp==3.11.12",
15
+ ]
16
+ readme = "README.md"
17
+ requires-python = ">= 3.8"
18
+
19
+ [project.scripts]
20
+ zucaro = "zucaro:main"
21
+
22
+ [build-system]
23
+ requires = ["hatchling"]
24
+ build-backend = "hatchling.build"
25
+
26
+ [tool.rye]
27
+ managed = true
28
+ dev-dependencies = []
29
+
30
+ [tool.hatch.metadata]
31
+ allow-direct-references = true
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/zucaro"]
35
+
36
+ [tool.ruff.lint]
37
+ extend-select = ["I", "W"]
@@ -0,0 +1,30 @@
1
+ # generated by rye
2
+ # use `rye lock` or `rye sync` to update this lockfile
3
+ #
4
+ # last locked with the following flags:
5
+ # pre: false
6
+ # features: []
7
+ # all-features: false
8
+ # with-sources: false
9
+
10
+ -e file:.
11
+ certifi==2024.2.2
12
+ # via requests
13
+ charset-normalizer==3.3.2
14
+ # via requests
15
+ click==8.1.7
16
+ # via zucaro
17
+ colorama==0.4.6
18
+ # via zucaro
19
+ coloredlogs==15.0.1
20
+ # via zucaro
21
+ humanfriendly==10.0
22
+ # via coloredlogs
23
+ idna==3.7
24
+ # via requests
25
+ requests==2.31.0
26
+ # via zucaro
27
+ tqdm==4.66.2
28
+ # via zucaro
29
+ urllib3==2.2.1
30
+ # via requests
@@ -0,0 +1,30 @@
1
+ # generated by rye
2
+ # use `rye lock` or `rye sync` to update this lockfile
3
+ #
4
+ # last locked with the following flags:
5
+ # pre: false
6
+ # features: []
7
+ # all-features: false
8
+ # with-sources: false
9
+
10
+ -e file:.
11
+ certifi==2024.2.2
12
+ # via requests
13
+ charset-normalizer==3.3.2
14
+ # via requests
15
+ click==8.1.7
16
+ # via zucaro
17
+ colorama==0.4.6
18
+ # via zucaro
19
+ coloredlogs==15.0.1
20
+ # via zucaro
21
+ humanfriendly==10.0
22
+ # via coloredlogs
23
+ idna==3.7
24
+ # via requests
25
+ requests==2.31.0
26
+ # via zucaro
27
+ tqdm==4.66.2
28
+ # via zucaro
29
+ urllib3==2.2.1
30
+ # via requests
@@ -0,0 +1,16 @@
1
+ import sys
2
+
3
+ from zucaro.cli import zucaro_cli
4
+
5
+ MINPYVERSION = (3, 7, 0)
6
+
7
+ if sys.version_info < MINPYVERSION:
8
+ print(
9
+ "zucaro requires at least Python version "
10
+ "{}.{}.{}. You are using {}.{}.{}.".format(*MINPYVERSION, *sys.version_info)
11
+ )
12
+ sys.exit(1)
13
+
14
+
15
+ def main():
16
+ zucaro_cli()
@@ -0,0 +1,6 @@
1
+ #!/bin/python
2
+
3
+ if __name__ == "__main__":
4
+ from zucaro import main
5
+
6
+ main()
@@ -0,0 +1,232 @@
1
+ import uuid
2
+ import aiohttp
3
+ import asyncio
4
+ from zucaro.errors import RefreshError, ValidationError
5
+ from zucaro.logging import logger
6
+ from zucaro.msapi import MicrosoftAuthApi
7
+ from zucaro.yggdrasil import MojangYggdrasil
8
+
9
+
10
+ class NAMESPACE_NULL:
11
+ bytes = b""
12
+
13
+
14
+ def generate_client_token():
15
+ # Any random string, this matches the behavior of the official launcher.
16
+ return str(uuid.uuid4().hex)
17
+
18
+
19
+ class Account:
20
+ def __init__(self, **kwargs):
21
+ self.__dict__.update(self.DEFAULTS)
22
+ self.__dict__.update(kwargs)
23
+
24
+ def __repr__(self):
25
+ return self.name
26
+
27
+ def to_dict(self):
28
+ return {k: getattr(self, k) for k in self.DEFAULTS.keys()}
29
+
30
+ def save(self):
31
+ self._am.save(self)
32
+
33
+ @classmethod
34
+ def from_config(cls, am, name, config):
35
+ if config.get("microsoft", False):
36
+ c = MicrosoftAccount
37
+ elif config.get("online", False):
38
+ c = OnlineAccount
39
+ else:
40
+ c = OfflineAccount
41
+ return c(name=name, _am=am, **config)
42
+
43
+
44
+ class OfflineAccount(Account):
45
+ DEFAULTS = {"uuid": "-", "online": False}
46
+ access_token = "-"
47
+
48
+ @classmethod
49
+ def new(cls, am, name):
50
+ u = uuid.uuid3(NAMESPACE_NULL, "OfflinePlayer:{}".format(name)).hex
51
+ return cls(name=name, uuid=u, _am=am)
52
+
53
+ @property
54
+ def gname(self):
55
+ return self.name
56
+
57
+ async def refresh(self):
58
+ return False
59
+
60
+ def can_launch_game(self):
61
+ return True
62
+
63
+
64
+ class OnlineAccount(Account):
65
+ DEFAULTS = {
66
+ "uuid": "-",
67
+ "online": True,
68
+ "gname": "-",
69
+ "access_token": "-",
70
+ "is_authenticated": False,
71
+ "username": "-",
72
+ }
73
+
74
+ fresh = False
75
+
76
+ @classmethod
77
+ def new(cls, am, name, username):
78
+ return cls(name=name, username=username, _am=am)
79
+
80
+ async def validate(self):
81
+ r = await self._am.yggdrasil.validate(self.access_token)
82
+ if r:
83
+ self.fresh = True
84
+ return r
85
+
86
+ async def refresh(self, force=False):
87
+ if self.fresh and not force:
88
+ return False
89
+ if self.is_authenticated:
90
+ if await self.validate():
91
+ return
92
+ else:
93
+ try:
94
+ refresh = await self._am.yggdrasil.refresh(self.access_token)
95
+ self.access_token, self.uuid, self.gname = refresh
96
+ self.fresh = True
97
+ return True
98
+ except RefreshError as e:
99
+ logger.error(
100
+ "Failed to refresh access_token," " please authenticate again."
101
+ )
102
+ self.is_authenticated = False
103
+ raise e
104
+ finally:
105
+ self.save()
106
+ else:
107
+ raise AccountError("Not authenticated.")
108
+
109
+ async def authenticate(self, password):
110
+ self.access_token, self.uuid, self.gname = await self._am.yggdrasil.authenticate(
111
+ self.username, password
112
+ )
113
+ self.is_authenticated = True
114
+ self.fresh = True
115
+ self.save()
116
+
117
+ def can_launch_game(self):
118
+ return self.is_authenticated
119
+
120
+
121
+ class MicrosoftAccount(Account):
122
+ DEFAULTS = {
123
+ "uuid": "-",
124
+ "online": True,
125
+ "microsoft": True,
126
+ "gname": "-",
127
+ "access_token": "-",
128
+ "refresh_token": "-",
129
+ "is_authenticated": False,
130
+ }
131
+
132
+ @classmethod
133
+ def new(cls, am, name):
134
+ return cls(name=name, _am=am)
135
+
136
+ async def refresh(self, force=False):
137
+ if not self.is_authenticated:
138
+ raise RefreshError("Account is not authenticated, cannot refresh")
139
+ try:
140
+ valid = await self._am.msapi.validate(self.access_token)
141
+ except ValidationError as e:
142
+ raise RefreshError(e)
143
+ if valid:
144
+ logger.debug("msa: token still valid")
145
+ return False
146
+ else:
147
+ logger.debug("msa: token not valid anymore, refreshing")
148
+ self.access_token, self.refresh_token = await self._am.msapi.refresh(
149
+ self.refresh_token
150
+ )
151
+ self.save()
152
+ return True
153
+
154
+ async def authenticate(self):
155
+ self.access_token, self.refresh_token = await self._am.msapi.authenticate()
156
+ profile = await self._am.msapi.get_profile(self.access_token)
157
+ self.gname = profile["name"]
158
+ self.uuid = profile["id"]
159
+ self.is_authenticated = True
160
+ self.save()
161
+
162
+ def can_launch_game(self):
163
+ return self.is_authenticated
164
+
165
+
166
+ class AccountError(ValueError):
167
+ def __str__(self):
168
+ return " ".join(self.args)
169
+
170
+
171
+ DEFAULT_CONFIG = {
172
+ "default": None,
173
+ "accounts": {},
174
+ "client_token": generate_client_token(),
175
+ }
176
+
177
+
178
+ class AccountManager:
179
+ CONFIG_FILE = "accounts.json"
180
+
181
+ def __init__(self, launcher):
182
+ self.config = launcher.config_manager.get(self.CONFIG_FILE, init=DEFAULT_CONFIG)
183
+ self.yggdrasil = MojangYggdrasil(self.config["client_token"])
184
+ self.msapi = MicrosoftAuthApi()
185
+
186
+ def list(self):
187
+ return self.config["accounts"].keys()
188
+
189
+ def get(self, name):
190
+ try:
191
+ acc = Account.from_config(self, name, self.config["accounts"][name])
192
+ acc.is_default = self.config["default"] == name
193
+ return acc
194
+ except KeyError as ke:
195
+ raise AccountError("Account does not exist:", name) from ke
196
+
197
+ def exists(self, name):
198
+ return name in self.config["accounts"]
199
+
200
+ def get_default(self):
201
+ default = self.config["default"]
202
+ if not default:
203
+ raise AccountError("Default account not configured.")
204
+ return self.get(default)
205
+
206
+ def is_default(self, name):
207
+ return name == self.config["default"]
208
+
209
+ def set_default(self, account):
210
+ self.config["default"] = account.name
211
+
212
+ def add(self, account):
213
+ if self.exists(account.name):
214
+ raise AccountError("An account already exists with that name.")
215
+ if not self.config["default"] and not self.config["accounts"]:
216
+ self.config["default"] = account.name
217
+ self.save(account)
218
+
219
+ def save(self, account):
220
+ self.config["accounts"][account.name] = account.to_dict()
221
+ # HACK This doesn't trip the crappy dirty flag on config, set manually
222
+ self.config.dirty = True
223
+
224
+ def remove(self, name):
225
+ try:
226
+ if self.config["default"] == name:
227
+ self.config["default"] = None
228
+ del self.config["accounts"][name]
229
+ # HACK This doesn't trip the crappy dirty flag on config, set manually
230
+ self.config.dirty = True
231
+ except KeyError:
232
+ raise AccountError("Account does not exist:", name)
@@ -0,0 +1,14 @@
1
+ from .account import register_account_cli
2
+ from .config import register_config_cli
3
+ from .instance import register_instance_cli
4
+ from .main import zucaro_cli
5
+ from .mod import register_mod_cli
6
+ from .play import register_play_cli
7
+ from .version import register_version_cli
8
+
9
+ register_account_cli(zucaro_cli)
10
+ register_version_cli(zucaro_cli)
11
+ register_instance_cli(zucaro_cli)
12
+ register_config_cli(zucaro_cli)
13
+ register_mod_cli(zucaro_cli)
14
+ register_play_cli(zucaro_cli)
@@ -0,0 +1,127 @@
1
+ import click
2
+
3
+ from zucaro.account import (
4
+ AccountError,
5
+ MicrosoftAccount,
6
+ OfflineAccount,
7
+ OnlineAccount,
8
+ RefreshError,
9
+ )
10
+ from zucaro.cli.utils import pass_account_manager, coro
11
+ from zucaro.logging import logger
12
+ from zucaro.yggdrasil import AuthenticationError
13
+
14
+
15
+ def account_cmd(fn):
16
+ return click.argument("account")(fn)
17
+
18
+
19
+ @click.group()
20
+ def account_cli():
21
+ """Manage your accounts."""
22
+ pass
23
+
24
+
25
+ @account_cli.command("list")
26
+ @click.option("--ms", is_flag=True, help="List the online accounts")
27
+ @pass_account_manager
28
+ def _list(am, ms):
29
+ """List available accounts."""
30
+ alist = am.list()
31
+ if ms:
32
+ alist = [acc for acc in alist if isinstance(am.get(acc), MicrosoftAccount)]
33
+ if alist:
34
+ lines = ("{}{}".format("* " if am.is_default(u) else " ", u) for u in alist)
35
+ print("\n".join(lines))
36
+ else:
37
+ logger.info("No accounts.")
38
+
39
+
40
+ @account_cli.command()
41
+ @account_cmd
42
+ @click.argument("mojang_username", required=False)
43
+ @click.option("--ms", "--microsoft", "microsoft", is_flag=True, default=False)
44
+ @pass_account_manager
45
+ def create(am, account, mojang_username, microsoft):
46
+ """Create an account."""
47
+ try:
48
+ if mojang_username:
49
+ if microsoft:
50
+ logger.error("Do not use --microsoft with mojang_username argument")
51
+ return
52
+ acc = OnlineAccount.new(am, account, mojang_username)
53
+ elif microsoft:
54
+ acc = MicrosoftAccount.new(am, account)
55
+ else:
56
+ acc = OfflineAccount.new(am, account)
57
+ am.add(acc)
58
+ except AccountError as e:
59
+ logger.error("Could not create account: %s", e)
60
+
61
+
62
+ @account_cli.command()
63
+ @account_cmd
64
+ @pass_account_manager
65
+ @coro
66
+ async def authenticate(am, account):
67
+ """Retrieve access token from Mojang servers using password."""
68
+
69
+ try:
70
+ a = am.get(account)
71
+ except AccountError:
72
+ logger.error("AccountError", exc_info=True)
73
+ return
74
+
75
+ try:
76
+ if isinstance(a, OfflineAccount):
77
+ logger.error("Offline accounts cannot be authenticated")
78
+ elif isinstance(a, OnlineAccount):
79
+ import getpass
80
+
81
+ p = getpass.getpass("Password: ")
82
+ await a.authenticate(p) # Await the coroutine
83
+ elif isinstance(a, MicrosoftAccount):
84
+ await a.authenticate()
85
+ else:
86
+ logger.error("Unknown account type")
87
+ except AuthenticationError as e:
88
+ logger.error("Authentication failed: %s", e)
89
+
90
+
91
+ @account_cli.command()
92
+ @account_cmd
93
+ @pass_account_manager
94
+ def refresh(am, account):
95
+ """Refresh access token with Mojang servers."""
96
+ try:
97
+ a = am.get(account)
98
+ a.refresh()
99
+ except (AccountError, RefreshError) as e:
100
+ logger.error("Could not refresh account: %s", e)
101
+
102
+
103
+ @account_cli.command()
104
+ @account_cmd
105
+ @pass_account_manager
106
+ def remove(am, account):
107
+ """Remove the account."""
108
+ try:
109
+ am.remove(account)
110
+ except AccountError as e:
111
+ logger.error("Could not remove account: %s", e)
112
+
113
+
114
+ @account_cli.command()
115
+ @account_cmd
116
+ @pass_account_manager
117
+ def setdefault(am, account):
118
+ """Set the account as default."""
119
+ try:
120
+ default = am.get(account)
121
+ am.set_default(default)
122
+ except AccountError as e:
123
+ logger.error("Could not set default account: %s", e)
124
+
125
+
126
+ def register_account_cli(zucaro_cli):
127
+ zucaro_cli.add_command(account_cli, name="account")