morphe-builder 0.1.0__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.
- morphe_builder-0.1.0/LICENSE +21 -0
- morphe_builder-0.1.0/PKG-INFO +298 -0
- morphe_builder-0.1.0/README.md +272 -0
- morphe_builder-0.1.0/pyproject.toml +50 -0
- morphe_builder-0.1.0/setup.cfg +4 -0
- morphe_builder-0.1.0/src/morphe_builder/__init__.py +839 -0
- morphe_builder-0.1.0/src/morphe_builder/apkmirror.py +261 -0
- morphe_builder-0.1.0/src/morphe_builder/build.py +468 -0
- morphe_builder-0.1.0/src/morphe_builder/compatibility.py +450 -0
- morphe_builder-0.1.0/src/morphe_builder/config.py +363 -0
- morphe_builder-0.1.0/src/morphe_builder/merge.py +401 -0
- morphe_builder-0.1.0/src/morphe_builder/module.py +554 -0
- morphe_builder-0.1.0/src/morphe_builder/orchestrator.py +644 -0
- morphe_builder-0.1.0/src/morphe_builder/providers.py +371 -0
- morphe_builder-0.1.0/src/morphe_builder/release.py +409 -0
- morphe_builder-0.1.0/src/morphe_builder/toolchain.py +562 -0
- morphe_builder-0.1.0/src/morphe_builder/uptodown.py +283 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/PKG-INFO +298 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/SOURCES.txt +34 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/dependency_links.txt +1 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/entry_points.txt +2 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/requires.txt +2 -0
- morphe_builder-0.1.0/src/morphe_builder.egg-info/top_level.txt +1 -0
- morphe_builder-0.1.0/tests/test_apkmirror.py +183 -0
- morphe_builder-0.1.0/tests/test_build.py +474 -0
- morphe_builder-0.1.0/tests/test_configuration_and_compatibility.py +391 -0
- morphe_builder-0.1.0/tests/test_merge.py +323 -0
- morphe_builder-0.1.0/tests/test_module.py +273 -0
- morphe_builder-0.1.0/tests/test_morphe_builder.py +674 -0
- morphe_builder-0.1.0/tests/test_orchestrator.py +349 -0
- morphe_builder-0.1.0/tests/test_providers.py +218 -0
- morphe_builder-0.1.0/tests/test_release.py +183 -0
- morphe_builder-0.1.0/tests/test_security.py +152 -0
- morphe_builder-0.1.0/tests/test_toolchain.py +217 -0
- morphe_builder-0.1.0/tests/test_uptodown.py +173 -0
- morphe_builder-0.1.0/tests/test_workflows.py +150 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mikel Villota
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: morphe-builder
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Build verified Morphe-patched Android APKs and modules
|
|
5
|
+
Author: Mikel Villota
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://github.com/Villoh/morphe-builder#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/Villoh/morphe-builder/issues
|
|
9
|
+
Project-URL: Repository, https://github.com/Villoh/morphe-builder
|
|
10
|
+
Keywords: android,apk,morphe,patcher,revanced
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Requires-Python: <3.14,>=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: apkutils2==1.0.0
|
|
24
|
+
Requires-Dist: gplaydl==0.0.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<!-- markdownlint-disable MD013 -->
|
|
28
|
+
|
|
29
|
+
<div align="center">
|
|
30
|
+
|
|
31
|
+
# Morphe Builder
|
|
32
|
+
|
|
33
|
+
**Verified Morphe-patched Android builds from stock Google Play splits, configured in one TOML file.**
|
|
34
|
+
|
|
35
|
+
[](https://github.com/Villoh/morphe-builder/actions/workflows/daily-update.yml)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
[](https://openjdk.org/)
|
|
38
|
+
[](https://docs.astral.sh/uv/)
|
|
39
|
+
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
Morphe Builder downloads stock APK splits from Google Play, verifies their integrity and signing certificate, merges them, patches them with the [Morphe](https://github.com/MorpheApp/morphe-desktop) CLI, signs the result, and packages non-root APKs plus deterministic Magisk/KernelSU modules.
|
|
45
|
+
|
|
46
|
+
Every app, architecture, patch source, and tool version is declared in a single TOML file, so a fork can build its own release matrix in CI without touching Python code. Nothing untrusted is published: downloads stay in a temporary directory until manifest coverage, hashes, package identity, version, ABI, and signer all pass, and each published set carries deterministic provenance.
|
|
47
|
+
|
|
48
|
+
Google Play delivery uses [`gplaydl`](https://github.com/Villoh/gplaydl) (branch `integration`), with verified `direct`, `archive`, APKMirror, and Uptodown fallbacks.
|
|
49
|
+
|
|
50
|
+
## Requirements
|
|
51
|
+
|
|
52
|
+
| Requirement | Version | Notes |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| [`Python`](https://www.python.org/) | 3.11–3.13 | 3.11 minimum for standard-library `tomllib` |
|
|
55
|
+
| [`Java`](https://openjdk.org/) | 21+ | Required by Morphe CLI, APKEditor, and uber-apk-signer |
|
|
56
|
+
| [`uv`](https://docs.astral.sh/uv/) | latest | Only for development installs from source |
|
|
57
|
+
|
|
58
|
+
Windows and Linux are supported. See [`docs/security.md`](docs/security.md) for platform limits.
|
|
59
|
+
|
|
60
|
+
## Features
|
|
61
|
+
|
|
62
|
+
- **Verified downloads**: Google manifest coverage, safe paths, sizes, SHA-256 hashes, package identity, version, split requirements, ABI, and signing certificate are all checked before publication.
|
|
63
|
+
- **Signer pinning**: YouTube and YouTube Music require known Google signers; any app can pin its own `expected-signer` SHA-256.
|
|
64
|
+
- **Provider fallback**: fixed order `google-play → direct → archive → apkmirror → uptodown`; integrity failures stay terminal instead of falling through to a later provider.
|
|
65
|
+
- **Config-driven matrix**: apps, architectures, densities, patch sets, and module output live in TOML; no hardcoded app registry.
|
|
66
|
+
- **Per-app toolchains**: each app can override Morphe CLI version, patch source, and patch version, resolved and cached per `owner/repo@tag`.
|
|
67
|
+
- **Pinned, hashed tooling**: Morphe CLI, patches, APKEditor, and uber-apk-signer are resolved to exact tags with recorded asset hashes in `toolchain-provenance.json`.
|
|
68
|
+
- **Non-root APKs and modules**: deterministic Magisk/KernelSU modules that install matching stock, survive reboots, and receive updates from the Magisk app.
|
|
69
|
+
- **Reproducible provenance**: `provenance.json`, `build-summary.json`, `release-manifest.json`, and `CHANGELOG.md` record every source, version, and hash.
|
|
70
|
+
- **Atomic publication**: existing output is never overwritten; a failed job removes its temporary set and publishes nothing.
|
|
71
|
+
- **Verified CI releases**: daily update checks resolve upstream versions, skip unchanged builds, verify every artifact, and attach GitHub artifact attestations.
|
|
72
|
+
- **Secret-safe by design**: no committed credentials, no cached tokens or APK payloads, redacted error output.
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
Morphe Builder pins a reviewed `gplaydl` fork commit. PyPI cannot encode VCS dependency sources, and the unrelated upstream `gplaydl` package is incompatible, so install both packages in one resolver transaction.
|
|
77
|
+
|
|
78
|
+
Global tool install:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uv tool install \
|
|
82
|
+
--with "gplaydl @ git+https://github.com/Villoh/gplaydl.git@de7dfba240b09bc986523c1637ac672b0c295980" \
|
|
83
|
+
morphe-builder
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Into an existing environment:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python -m pip install \
|
|
90
|
+
morphe-builder \
|
|
91
|
+
"gplaydl @ git+https://github.com/Villoh/gplaydl.git@de7dfba240b09bc986523c1637ac672b0c295980"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Do not install `morphe-builder` without the pinned override: its `gplaydl==0.0.0` package requirement deliberately fails closed instead of selecting the incompatible PyPI distribution.
|
|
95
|
+
|
|
96
|
+
Development install from source:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
git clone https://github.com/Villoh/morphe-builder
|
|
100
|
+
cd morphe-builder
|
|
101
|
+
uv sync
|
|
102
|
+
uv run morphe-builder --help
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Quick start
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
morphe-builder auth --arch arm64
|
|
109
|
+
morphe-builder tools
|
|
110
|
+
MORPHE_KEYSTORE_PASSWORD=secret morphe-builder build morphe.toml \
|
|
111
|
+
--keystore /path/outside/repository/builder.p12 \
|
|
112
|
+
--output build
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`auth` stores Google Play credentials outside the repository, `tools` fetches and hashes the pinned Java toolchain, and `build` produces the full configured matrix from [`morphe.toml`](morphe.toml).
|
|
116
|
+
|
|
117
|
+
### Google Play access
|
|
118
|
+
|
|
119
|
+
Set these two together to download directly from Google's servers through the [`gplaydl`](https://github.com/Villoh/gplaydl) fork. This is the recommended setup: it is the only reliable path from CI runners, and it avoids the shared anonymous dispenser entirely.
|
|
120
|
+
|
|
121
|
+
| Variable | Value |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `GPLAYDL_ACCOUNT_EMAIL` | Google account email used for Play authentication. |
|
|
124
|
+
| `GPLAYDL_AAS_TOKEN` | Persistent AAS token for that account. Must start with `aas_et/`. |
|
|
125
|
+
|
|
126
|
+
A value starting with `g.a` is a temporary bearer token, not an AAS token, and is rejected. Both variables are required together; a partial configuration fails instead of silently falling back. Treat the token as a password: use a dedicated account, keep it only in environment variables or GitHub Environment secrets, and never place it in TOML, argv, or committed files. Changing the account password invalidates it.
|
|
127
|
+
|
|
128
|
+
<details>
|
|
129
|
+
<summary><b>How to generate an AAS token with <code>gplaydl</code></b></summary>
|
|
130
|
+
|
|
131
|
+
`gplaydl aastoken` prints a Google account AAS token. Credentials and tokens are used in memory only; no `credentials.txt` or `token.txt` file is created.
|
|
132
|
+
|
|
133
|
+
**OAuth mode (recommended)**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
gplaydl aastoken --oauth
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Get the required one-time `oauth_token`:
|
|
140
|
+
|
|
141
|
+
1. Open Google [EmbeddedSetup](https://accounts.google.com/EmbeddedSetup).
|
|
142
|
+
2. Sign in and select **I agree**.
|
|
143
|
+
3. The page may stay frozen or loading forever. This is expected; the cookie is normally already available.
|
|
144
|
+
4. Open browser developer tools (<kbd>F12</kbd>).
|
|
145
|
+
5. In Chrome or Edge, open **Application › Cookies › `https://accounts.google.com`**.
|
|
146
|
+
6. Copy the value of the `oauth_token` cookie. It starts with `oauth2_4/`.
|
|
147
|
+
7. Run `gplaydl aastoken --oauth`, enter the same email, then paste the token. Both inputs are handled interactively and the token is hidden.
|
|
148
|
+
|
|
149
|
+
The `oauth_token` is short-lived and single-use. The resulting AAS token is printed to the console.
|
|
150
|
+
|
|
151
|
+
**Password or app-password mode**
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Interactive: asks for email and hides password input
|
|
155
|
+
gplaydl aastoken
|
|
156
|
+
|
|
157
|
+
# Arguments: convenient, but password remains in shell history
|
|
158
|
+
gplaydl aastoken user@example.com password
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Google commonly rejects both account passwords and 16-character app passwords with `BadAuthentication`. Keep 2-Step Verification enabled and use OAuth mode instead.
|
|
162
|
+
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
Without these variables, `gplaydl` falls back to the public anonymous dispenser, which is frequently blocked from datacenter IP ranges. In that case the builder continues through the verified APKMirror and Uptodown fallbacks declared in your configuration.
|
|
166
|
+
|
|
167
|
+
### Other environment variables
|
|
168
|
+
|
|
169
|
+
| Variable | Used by | Purpose |
|
|
170
|
+
| --- | --- | --- |
|
|
171
|
+
| `MORPHE_KEYSTORE_PASSWORD` | `build` | Signing keystore password. Required; never accepted in argv. |
|
|
172
|
+
| `MORPHE_DISPENSER_URL` | `auth`, `download` | Custom anonymous dispenser, used only when no Google account is configured. |
|
|
173
|
+
| `MORPHE_MODULE_VERSION_CODE` | `build` | Monotonic module `versionCode`. CI passes the workflow run number. |
|
|
174
|
+
| `GITHUB_TOKEN` | `tools`, `build`, `list-patches` | Authenticates GitHub API calls. Never sent to asset downloads. |
|
|
175
|
+
| `HTTP_PROXY`, `HTTPS_PROXY` | `build` | Proxy for provider downloads. |
|
|
176
|
+
| `XDG_CACHE_HOME`, `LOCALAPPDATA` | all cached commands | Override the default cache root. |
|
|
177
|
+
|
|
178
|
+
## Configuration
|
|
179
|
+
|
|
180
|
+
Everything a fork needs to change lives in [`morphe.toml`](morphe.toml). No Python code has to be touched to build a different set of apps.
|
|
181
|
+
|
|
182
|
+
The file has one `[toolchain]` table with the default Morphe CLI and patch sources, then one ordered `[[apps]]` entry per app:
|
|
183
|
+
|
|
184
|
+
```toml
|
|
185
|
+
[toolchain]
|
|
186
|
+
morphe-source = "MorpheApp/morphe-desktop"
|
|
187
|
+
morphe-version = "latest"
|
|
188
|
+
patches-source = "MorpheApp/morphe-patches"
|
|
189
|
+
patches-version = "latest"
|
|
190
|
+
|
|
191
|
+
[[apps]]
|
|
192
|
+
package = "com.google.android.youtube"
|
|
193
|
+
name = "YouTube"
|
|
194
|
+
slug = "youtube"
|
|
195
|
+
patched-package = "app.morphe.android.youtube"
|
|
196
|
+
version = "auto"
|
|
197
|
+
build-mode = "apk"
|
|
198
|
+
arch = "arm64-v8a"
|
|
199
|
+
density = "xxhdpi"
|
|
200
|
+
include-patches = ["GmsCore support", "SponsorBlock"]
|
|
201
|
+
exclude-patches = []
|
|
202
|
+
|
|
203
|
+
[apps.patch-options."SponsorBlock"]
|
|
204
|
+
toast-on-connection-error = true
|
|
205
|
+
|
|
206
|
+
[apps.google-play]
|
|
207
|
+
profile = "D2"
|
|
208
|
+
country = "US"
|
|
209
|
+
|
|
210
|
+
[apps.fallbacks]
|
|
211
|
+
apkmirror = ["https://www.apkmirror.com/apk/google-inc/youtube/"]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Only `package` and `name` are required. Everything else has a documented default:
|
|
215
|
+
|
|
216
|
+
| Setting | Required | Default when omitted |
|
|
217
|
+
| --- | :---: | --- |
|
|
218
|
+
| `package` | yes | Validated Android package name. |
|
|
219
|
+
| `name` | yes | Display name used in release notes and modules. |
|
|
220
|
+
| `slug` | no | `package` with dots replaced by hyphens. Controls output, cache, and module names; must be unique. |
|
|
221
|
+
| `patched-package` | no | No package change is expected after patching. Set it when patches rename the package. |
|
|
222
|
+
| `version` | no | `auto`: highest version supported by every selected patch. Also accepts `latest` or an exact version name. |
|
|
223
|
+
| `version-code` | no | Resolved from the version name. Requires an explicit `version`; `auto` and `latest` are rejected with it. |
|
|
224
|
+
| `build-mode` | no | `apk`: non-root APK only. Use `module` or `both` for Magisk/KernelSU modules. |
|
|
225
|
+
| `arch` | no | `arm64-v8a`. Also `arm-v7a`, `all`, or `both` (two independent jobs). |
|
|
226
|
+
| `density` | no | The profile's only available density split is selected automatically. |
|
|
227
|
+
| `include-patches` | no | Empty: the patch bundle's default selection is used. |
|
|
228
|
+
| `exclude-patches` | no | Empty: nothing is removed from the selection. |
|
|
229
|
+
| `exclusive-patches` | no | Unset. When set, only these patches apply; cannot be combined with include/exclude. |
|
|
230
|
+
| `patch-options` | no | Patch defaults. Scalar values only, never shell-interpolated. Every option must belong to a selected patch. |
|
|
231
|
+
| `expected-signer` | no | Unpinned: a valid provider-served signer is accepted and logged as `unpinned signer accepted`. YouTube and YouTube Music always enforce built-in Google signer pins. |
|
|
232
|
+
| `google-play.profile` | no | `gplaydl` picks a profile. Leave unset with `arch = "both"`, since one profile cannot cover both ABIs. |
|
|
233
|
+
| `google-play.country` | no | `gplaydl` account region. |
|
|
234
|
+
| `google-play.proxy` | no | Direct connection. |
|
|
235
|
+
| `google-play.dispenser` | no | `MORPHE_DISPENSER_URL`, or the built-in public dispenser. |
|
|
236
|
+
| `fallbacks.*` | no | Empty: Google Play is the only source, so a Play failure fails the job. |
|
|
237
|
+
| `patches-source`, `patches-version`, `cli-source`, `morphe-version` | no | The `[toolchain]` values. |
|
|
238
|
+
|
|
239
|
+
The `[toolchain]` table itself is optional; omitting it uses `MorpheApp/morphe-desktop` and `MorpheApp/morphe-patches` at `latest`.
|
|
240
|
+
|
|
241
|
+
Parsing is strict: unknown keys, duplicate packages, duplicate slugs, unsupported values, and conflicting patch selections are all rejected before any download starts. Run `morphe-builder list-patches morphe.toml` to see which version each app will resolve to before committing a change.
|
|
242
|
+
|
|
243
|
+
For CI-built releases, declare at least one `fallbacks` entry per app. Anonymous Google Play access is unreliable from hosted runners, and a verified APKMirror or Uptodown source keeps the build working without credentials.
|
|
244
|
+
|
|
245
|
+
Full field reference, version-resolution order, and fallback URL rules: [`docs/configuration.md`](docs/configuration.md).
|
|
246
|
+
|
|
247
|
+
## Usage
|
|
248
|
+
|
|
249
|
+
| Command | Purpose |
|
|
250
|
+
| --- | --- |
|
|
251
|
+
| `auth` | Authenticate against Google Play and cache the session outside the repository. |
|
|
252
|
+
| `download` | Download and verify one package's splits into an output directory. |
|
|
253
|
+
| `tools` | Resolve, download, and hash the pinned Java toolchain. |
|
|
254
|
+
| `list-patches` | Show patch-compatible versions for the configured apps. |
|
|
255
|
+
| `build` | Run the full configured matrix: download, merge, patch, sign, verify, package. |
|
|
256
|
+
| `verify` | Re-verify an existing split set against a package, architecture, and version. |
|
|
257
|
+
| `clean` | Remove the disposable work cache only; trusted sets and tools are preserved. |
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
morphe-builder download com.example.app --arch arm64 --output downloads
|
|
261
|
+
morphe-builder list-patches morphe.toml
|
|
262
|
+
morphe-builder verify trusted/splits com.google.android.youtube \
|
|
263
|
+
--arch arm64 --version-name 21.04.223
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
All commands accept `--json` (progress on stderr, machine-readable result on stdout). `--arch both` runs independent ARM64 and ARMv7 jobs. Keystore passwords come from `MORPHE_KEYSTORE_PASSWORD`, never argv. Exit codes are stable per failure category.
|
|
267
|
+
|
|
268
|
+
Full reference, exit-code table, and cache semantics: [`docs/cli.md`](docs/cli.md).
|
|
269
|
+
|
|
270
|
+
## Documentation
|
|
271
|
+
|
|
272
|
+
| Topic | Document |
|
|
273
|
+
| --- | --- |
|
|
274
|
+
| CLI reference and exit codes | [`docs/cli.md`](docs/cli.md) |
|
|
275
|
+
| TOML configuration and version resolution | [`docs/configuration.md`](docs/configuration.md) |
|
|
276
|
+
| Toolchain cache, pins, and checksums | [`docs/toolchain.md`](docs/toolchain.md) |
|
|
277
|
+
| Google Play delivery and integrity checks | [`docs/google-play-integrity.md`](docs/google-play-integrity.md) |
|
|
278
|
+
| Provider fallback order | [`docs/providers.md`](docs/providers.md) |
|
|
279
|
+
| Split selection and merge policy | [`docs/merge.md`](docs/merge.md) |
|
|
280
|
+
| Signed APK build flow | [`docs/build.md`](docs/build.md) |
|
|
281
|
+
| Magisk/KernelSU module format | [`docs/modules.md`](docs/modules.md) |
|
|
282
|
+
| Threat model and platform limits | [`docs/security.md`](docs/security.md) |
|
|
283
|
+
| CI, release verification, and publication | [`docs/releases.md`](docs/releases.md) |
|
|
284
|
+
| Third-party licenses | [`docs/THIRD_PARTY.md`](docs/THIRD_PARTY.md) |
|
|
285
|
+
| Repository rules for contributors and agents | [`docs/rules/README.md`](docs/rules/README.md) |
|
|
286
|
+
| Active roadmap | [`docs/roadmap/ROADMAP.md`](docs/roadmap/ROADMAP.md) |
|
|
287
|
+
| Completed milestones and evidence | [`docs/roadmap/COMPLETED.md`](docs/roadmap/COMPLETED.md) |
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
Morphe Builder is released under the [MIT License](LICENSE). Downloaded Morphe tooling remains separately licensed under GPL-3.0 and is not bundled in the Python distribution. See [`docs/THIRD_PARTY.md`](docs/THIRD_PARTY.md).
|
|
292
|
+
|
|
293
|
+
## Credits
|
|
294
|
+
|
|
295
|
+
- [`MorpheApp/morphe-desktop`](https://github.com/MorpheApp/morphe-desktop) and [`MorpheApp/morphe-patches`](https://github.com/MorpheApp/morphe-patches): the patching CLI and patch bundles this builder orchestrates. Morphe does the patching; this project only prepares verified stock input and packages the output.
|
|
296
|
+
- [`j-hc/revanced-magisk-module`](https://github.com/j-hc/revanced-magisk-module): prior art for the Magisk/KernelSU module approach and CI build matrix. Reviewed as design context under GPL-3.0; no code is copied. See [`docs/modules.md`](docs/modules.md).
|
|
297
|
+
- [`REAndroid/APKEditor`](https://github.com/REAndroid/APKEditor) and [`patrickfav/uber-apk-signer`](https://github.com/patrickfav/uber-apk-signer): split merge and APK signing tools.
|
|
298
|
+
- [ReVanced](https://revanced.app/): the patch ecosystem Morphe builds on; ReVanced-compatible patch bundles can be selected per app via `patches-source`.
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
<!-- markdownlint-disable MD013 -->
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
# Morphe Builder
|
|
6
|
+
|
|
7
|
+
**Verified Morphe-patched Android builds from stock Google Play splits, configured in one TOML file.**
|
|
8
|
+
|
|
9
|
+
[](https://github.com/Villoh/morphe-builder/actions/workflows/daily-update.yml)
|
|
10
|
+
[](https://www.python.org/)
|
|
11
|
+
[](https://openjdk.org/)
|
|
12
|
+
[](https://docs.astral.sh/uv/)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Morphe Builder downloads stock APK splits from Google Play, verifies their integrity and signing certificate, merges them, patches them with the [Morphe](https://github.com/MorpheApp/morphe-desktop) CLI, signs the result, and packages non-root APKs plus deterministic Magisk/KernelSU modules.
|
|
19
|
+
|
|
20
|
+
Every app, architecture, patch source, and tool version is declared in a single TOML file, so a fork can build its own release matrix in CI without touching Python code. Nothing untrusted is published: downloads stay in a temporary directory until manifest coverage, hashes, package identity, version, ABI, and signer all pass, and each published set carries deterministic provenance.
|
|
21
|
+
|
|
22
|
+
Google Play delivery uses [`gplaydl`](https://github.com/Villoh/gplaydl) (branch `integration`), with verified `direct`, `archive`, APKMirror, and Uptodown fallbacks.
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
| Requirement | Version | Notes |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| [`Python`](https://www.python.org/) | 3.11–3.13 | 3.11 minimum for standard-library `tomllib` |
|
|
29
|
+
| [`Java`](https://openjdk.org/) | 21+ | Required by Morphe CLI, APKEditor, and uber-apk-signer |
|
|
30
|
+
| [`uv`](https://docs.astral.sh/uv/) | latest | Only for development installs from source |
|
|
31
|
+
|
|
32
|
+
Windows and Linux are supported. See [`docs/security.md`](docs/security.md) for platform limits.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Verified downloads**: Google manifest coverage, safe paths, sizes, SHA-256 hashes, package identity, version, split requirements, ABI, and signing certificate are all checked before publication.
|
|
37
|
+
- **Signer pinning**: YouTube and YouTube Music require known Google signers; any app can pin its own `expected-signer` SHA-256.
|
|
38
|
+
- **Provider fallback**: fixed order `google-play → direct → archive → apkmirror → uptodown`; integrity failures stay terminal instead of falling through to a later provider.
|
|
39
|
+
- **Config-driven matrix**: apps, architectures, densities, patch sets, and module output live in TOML; no hardcoded app registry.
|
|
40
|
+
- **Per-app toolchains**: each app can override Morphe CLI version, patch source, and patch version, resolved and cached per `owner/repo@tag`.
|
|
41
|
+
- **Pinned, hashed tooling**: Morphe CLI, patches, APKEditor, and uber-apk-signer are resolved to exact tags with recorded asset hashes in `toolchain-provenance.json`.
|
|
42
|
+
- **Non-root APKs and modules**: deterministic Magisk/KernelSU modules that install matching stock, survive reboots, and receive updates from the Magisk app.
|
|
43
|
+
- **Reproducible provenance**: `provenance.json`, `build-summary.json`, `release-manifest.json`, and `CHANGELOG.md` record every source, version, and hash.
|
|
44
|
+
- **Atomic publication**: existing output is never overwritten; a failed job removes its temporary set and publishes nothing.
|
|
45
|
+
- **Verified CI releases**: daily update checks resolve upstream versions, skip unchanged builds, verify every artifact, and attach GitHub artifact attestations.
|
|
46
|
+
- **Secret-safe by design**: no committed credentials, no cached tokens or APK payloads, redacted error output.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Morphe Builder pins a reviewed `gplaydl` fork commit. PyPI cannot encode VCS dependency sources, and the unrelated upstream `gplaydl` package is incompatible, so install both packages in one resolver transaction.
|
|
51
|
+
|
|
52
|
+
Global tool install:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv tool install \
|
|
56
|
+
--with "gplaydl @ git+https://github.com/Villoh/gplaydl.git@de7dfba240b09bc986523c1637ac672b0c295980" \
|
|
57
|
+
morphe-builder
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Into an existing environment:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python -m pip install \
|
|
64
|
+
morphe-builder \
|
|
65
|
+
"gplaydl @ git+https://github.com/Villoh/gplaydl.git@de7dfba240b09bc986523c1637ac672b0c295980"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Do not install `morphe-builder` without the pinned override: its `gplaydl==0.0.0` package requirement deliberately fails closed instead of selecting the incompatible PyPI distribution.
|
|
69
|
+
|
|
70
|
+
Development install from source:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/Villoh/morphe-builder
|
|
74
|
+
cd morphe-builder
|
|
75
|
+
uv sync
|
|
76
|
+
uv run morphe-builder --help
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
morphe-builder auth --arch arm64
|
|
83
|
+
morphe-builder tools
|
|
84
|
+
MORPHE_KEYSTORE_PASSWORD=secret morphe-builder build morphe.toml \
|
|
85
|
+
--keystore /path/outside/repository/builder.p12 \
|
|
86
|
+
--output build
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`auth` stores Google Play credentials outside the repository, `tools` fetches and hashes the pinned Java toolchain, and `build` produces the full configured matrix from [`morphe.toml`](morphe.toml).
|
|
90
|
+
|
|
91
|
+
### Google Play access
|
|
92
|
+
|
|
93
|
+
Set these two together to download directly from Google's servers through the [`gplaydl`](https://github.com/Villoh/gplaydl) fork. This is the recommended setup: it is the only reliable path from CI runners, and it avoids the shared anonymous dispenser entirely.
|
|
94
|
+
|
|
95
|
+
| Variable | Value |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `GPLAYDL_ACCOUNT_EMAIL` | Google account email used for Play authentication. |
|
|
98
|
+
| `GPLAYDL_AAS_TOKEN` | Persistent AAS token for that account. Must start with `aas_et/`. |
|
|
99
|
+
|
|
100
|
+
A value starting with `g.a` is a temporary bearer token, not an AAS token, and is rejected. Both variables are required together; a partial configuration fails instead of silently falling back. Treat the token as a password: use a dedicated account, keep it only in environment variables or GitHub Environment secrets, and never place it in TOML, argv, or committed files. Changing the account password invalidates it.
|
|
101
|
+
|
|
102
|
+
<details>
|
|
103
|
+
<summary><b>How to generate an AAS token with <code>gplaydl</code></b></summary>
|
|
104
|
+
|
|
105
|
+
`gplaydl aastoken` prints a Google account AAS token. Credentials and tokens are used in memory only; no `credentials.txt` or `token.txt` file is created.
|
|
106
|
+
|
|
107
|
+
**OAuth mode (recommended)**
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
gplaydl aastoken --oauth
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Get the required one-time `oauth_token`:
|
|
114
|
+
|
|
115
|
+
1. Open Google [EmbeddedSetup](https://accounts.google.com/EmbeddedSetup).
|
|
116
|
+
2. Sign in and select **I agree**.
|
|
117
|
+
3. The page may stay frozen or loading forever. This is expected; the cookie is normally already available.
|
|
118
|
+
4. Open browser developer tools (<kbd>F12</kbd>).
|
|
119
|
+
5. In Chrome or Edge, open **Application › Cookies › `https://accounts.google.com`**.
|
|
120
|
+
6. Copy the value of the `oauth_token` cookie. It starts with `oauth2_4/`.
|
|
121
|
+
7. Run `gplaydl aastoken --oauth`, enter the same email, then paste the token. Both inputs are handled interactively and the token is hidden.
|
|
122
|
+
|
|
123
|
+
The `oauth_token` is short-lived and single-use. The resulting AAS token is printed to the console.
|
|
124
|
+
|
|
125
|
+
**Password or app-password mode**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Interactive: asks for email and hides password input
|
|
129
|
+
gplaydl aastoken
|
|
130
|
+
|
|
131
|
+
# Arguments: convenient, but password remains in shell history
|
|
132
|
+
gplaydl aastoken user@example.com password
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Google commonly rejects both account passwords and 16-character app passwords with `BadAuthentication`. Keep 2-Step Verification enabled and use OAuth mode instead.
|
|
136
|
+
|
|
137
|
+
</details>
|
|
138
|
+
|
|
139
|
+
Without these variables, `gplaydl` falls back to the public anonymous dispenser, which is frequently blocked from datacenter IP ranges. In that case the builder continues through the verified APKMirror and Uptodown fallbacks declared in your configuration.
|
|
140
|
+
|
|
141
|
+
### Other environment variables
|
|
142
|
+
|
|
143
|
+
| Variable | Used by | Purpose |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| `MORPHE_KEYSTORE_PASSWORD` | `build` | Signing keystore password. Required; never accepted in argv. |
|
|
146
|
+
| `MORPHE_DISPENSER_URL` | `auth`, `download` | Custom anonymous dispenser, used only when no Google account is configured. |
|
|
147
|
+
| `MORPHE_MODULE_VERSION_CODE` | `build` | Monotonic module `versionCode`. CI passes the workflow run number. |
|
|
148
|
+
| `GITHUB_TOKEN` | `tools`, `build`, `list-patches` | Authenticates GitHub API calls. Never sent to asset downloads. |
|
|
149
|
+
| `HTTP_PROXY`, `HTTPS_PROXY` | `build` | Proxy for provider downloads. |
|
|
150
|
+
| `XDG_CACHE_HOME`, `LOCALAPPDATA` | all cached commands | Override the default cache root. |
|
|
151
|
+
|
|
152
|
+
## Configuration
|
|
153
|
+
|
|
154
|
+
Everything a fork needs to change lives in [`morphe.toml`](morphe.toml). No Python code has to be touched to build a different set of apps.
|
|
155
|
+
|
|
156
|
+
The file has one `[toolchain]` table with the default Morphe CLI and patch sources, then one ordered `[[apps]]` entry per app:
|
|
157
|
+
|
|
158
|
+
```toml
|
|
159
|
+
[toolchain]
|
|
160
|
+
morphe-source = "MorpheApp/morphe-desktop"
|
|
161
|
+
morphe-version = "latest"
|
|
162
|
+
patches-source = "MorpheApp/morphe-patches"
|
|
163
|
+
patches-version = "latest"
|
|
164
|
+
|
|
165
|
+
[[apps]]
|
|
166
|
+
package = "com.google.android.youtube"
|
|
167
|
+
name = "YouTube"
|
|
168
|
+
slug = "youtube"
|
|
169
|
+
patched-package = "app.morphe.android.youtube"
|
|
170
|
+
version = "auto"
|
|
171
|
+
build-mode = "apk"
|
|
172
|
+
arch = "arm64-v8a"
|
|
173
|
+
density = "xxhdpi"
|
|
174
|
+
include-patches = ["GmsCore support", "SponsorBlock"]
|
|
175
|
+
exclude-patches = []
|
|
176
|
+
|
|
177
|
+
[apps.patch-options."SponsorBlock"]
|
|
178
|
+
toast-on-connection-error = true
|
|
179
|
+
|
|
180
|
+
[apps.google-play]
|
|
181
|
+
profile = "D2"
|
|
182
|
+
country = "US"
|
|
183
|
+
|
|
184
|
+
[apps.fallbacks]
|
|
185
|
+
apkmirror = ["https://www.apkmirror.com/apk/google-inc/youtube/"]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Only `package` and `name` are required. Everything else has a documented default:
|
|
189
|
+
|
|
190
|
+
| Setting | Required | Default when omitted |
|
|
191
|
+
| --- | :---: | --- |
|
|
192
|
+
| `package` | yes | Validated Android package name. |
|
|
193
|
+
| `name` | yes | Display name used in release notes and modules. |
|
|
194
|
+
| `slug` | no | `package` with dots replaced by hyphens. Controls output, cache, and module names; must be unique. |
|
|
195
|
+
| `patched-package` | no | No package change is expected after patching. Set it when patches rename the package. |
|
|
196
|
+
| `version` | no | `auto`: highest version supported by every selected patch. Also accepts `latest` or an exact version name. |
|
|
197
|
+
| `version-code` | no | Resolved from the version name. Requires an explicit `version`; `auto` and `latest` are rejected with it. |
|
|
198
|
+
| `build-mode` | no | `apk`: non-root APK only. Use `module` or `both` for Magisk/KernelSU modules. |
|
|
199
|
+
| `arch` | no | `arm64-v8a`. Also `arm-v7a`, `all`, or `both` (two independent jobs). |
|
|
200
|
+
| `density` | no | The profile's only available density split is selected automatically. |
|
|
201
|
+
| `include-patches` | no | Empty: the patch bundle's default selection is used. |
|
|
202
|
+
| `exclude-patches` | no | Empty: nothing is removed from the selection. |
|
|
203
|
+
| `exclusive-patches` | no | Unset. When set, only these patches apply; cannot be combined with include/exclude. |
|
|
204
|
+
| `patch-options` | no | Patch defaults. Scalar values only, never shell-interpolated. Every option must belong to a selected patch. |
|
|
205
|
+
| `expected-signer` | no | Unpinned: a valid provider-served signer is accepted and logged as `unpinned signer accepted`. YouTube and YouTube Music always enforce built-in Google signer pins. |
|
|
206
|
+
| `google-play.profile` | no | `gplaydl` picks a profile. Leave unset with `arch = "both"`, since one profile cannot cover both ABIs. |
|
|
207
|
+
| `google-play.country` | no | `gplaydl` account region. |
|
|
208
|
+
| `google-play.proxy` | no | Direct connection. |
|
|
209
|
+
| `google-play.dispenser` | no | `MORPHE_DISPENSER_URL`, or the built-in public dispenser. |
|
|
210
|
+
| `fallbacks.*` | no | Empty: Google Play is the only source, so a Play failure fails the job. |
|
|
211
|
+
| `patches-source`, `patches-version`, `cli-source`, `morphe-version` | no | The `[toolchain]` values. |
|
|
212
|
+
|
|
213
|
+
The `[toolchain]` table itself is optional; omitting it uses `MorpheApp/morphe-desktop` and `MorpheApp/morphe-patches` at `latest`.
|
|
214
|
+
|
|
215
|
+
Parsing is strict: unknown keys, duplicate packages, duplicate slugs, unsupported values, and conflicting patch selections are all rejected before any download starts. Run `morphe-builder list-patches morphe.toml` to see which version each app will resolve to before committing a change.
|
|
216
|
+
|
|
217
|
+
For CI-built releases, declare at least one `fallbacks` entry per app. Anonymous Google Play access is unreliable from hosted runners, and a verified APKMirror or Uptodown source keeps the build working without credentials.
|
|
218
|
+
|
|
219
|
+
Full field reference, version-resolution order, and fallback URL rules: [`docs/configuration.md`](docs/configuration.md).
|
|
220
|
+
|
|
221
|
+
## Usage
|
|
222
|
+
|
|
223
|
+
| Command | Purpose |
|
|
224
|
+
| --- | --- |
|
|
225
|
+
| `auth` | Authenticate against Google Play and cache the session outside the repository. |
|
|
226
|
+
| `download` | Download and verify one package's splits into an output directory. |
|
|
227
|
+
| `tools` | Resolve, download, and hash the pinned Java toolchain. |
|
|
228
|
+
| `list-patches` | Show patch-compatible versions for the configured apps. |
|
|
229
|
+
| `build` | Run the full configured matrix: download, merge, patch, sign, verify, package. |
|
|
230
|
+
| `verify` | Re-verify an existing split set against a package, architecture, and version. |
|
|
231
|
+
| `clean` | Remove the disposable work cache only; trusted sets and tools are preserved. |
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
morphe-builder download com.example.app --arch arm64 --output downloads
|
|
235
|
+
morphe-builder list-patches morphe.toml
|
|
236
|
+
morphe-builder verify trusted/splits com.google.android.youtube \
|
|
237
|
+
--arch arm64 --version-name 21.04.223
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
All commands accept `--json` (progress on stderr, machine-readable result on stdout). `--arch both` runs independent ARM64 and ARMv7 jobs. Keystore passwords come from `MORPHE_KEYSTORE_PASSWORD`, never argv. Exit codes are stable per failure category.
|
|
241
|
+
|
|
242
|
+
Full reference, exit-code table, and cache semantics: [`docs/cli.md`](docs/cli.md).
|
|
243
|
+
|
|
244
|
+
## Documentation
|
|
245
|
+
|
|
246
|
+
| Topic | Document |
|
|
247
|
+
| --- | --- |
|
|
248
|
+
| CLI reference and exit codes | [`docs/cli.md`](docs/cli.md) |
|
|
249
|
+
| TOML configuration and version resolution | [`docs/configuration.md`](docs/configuration.md) |
|
|
250
|
+
| Toolchain cache, pins, and checksums | [`docs/toolchain.md`](docs/toolchain.md) |
|
|
251
|
+
| Google Play delivery and integrity checks | [`docs/google-play-integrity.md`](docs/google-play-integrity.md) |
|
|
252
|
+
| Provider fallback order | [`docs/providers.md`](docs/providers.md) |
|
|
253
|
+
| Split selection and merge policy | [`docs/merge.md`](docs/merge.md) |
|
|
254
|
+
| Signed APK build flow | [`docs/build.md`](docs/build.md) |
|
|
255
|
+
| Magisk/KernelSU module format | [`docs/modules.md`](docs/modules.md) |
|
|
256
|
+
| Threat model and platform limits | [`docs/security.md`](docs/security.md) |
|
|
257
|
+
| CI, release verification, and publication | [`docs/releases.md`](docs/releases.md) |
|
|
258
|
+
| Third-party licenses | [`docs/THIRD_PARTY.md`](docs/THIRD_PARTY.md) |
|
|
259
|
+
| Repository rules for contributors and agents | [`docs/rules/README.md`](docs/rules/README.md) |
|
|
260
|
+
| Active roadmap | [`docs/roadmap/ROADMAP.md`](docs/roadmap/ROADMAP.md) |
|
|
261
|
+
| Completed milestones and evidence | [`docs/roadmap/COMPLETED.md`](docs/roadmap/COMPLETED.md) |
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
Morphe Builder is released under the [MIT License](LICENSE). Downloaded Morphe tooling remains separately licensed under GPL-3.0 and is not bundled in the Python distribution. See [`docs/THIRD_PARTY.md`](docs/THIRD_PARTY.md).
|
|
266
|
+
|
|
267
|
+
## Credits
|
|
268
|
+
|
|
269
|
+
- [`MorpheApp/morphe-desktop`](https://github.com/MorpheApp/morphe-desktop) and [`MorpheApp/morphe-patches`](https://github.com/MorpheApp/morphe-patches): the patching CLI and patch bundles this builder orchestrates. Morphe does the patching; this project only prepares verified stock input and packages the output.
|
|
270
|
+
- [`j-hc/revanced-magisk-module`](https://github.com/j-hc/revanced-magisk-module): prior art for the Magisk/KernelSU module approach and CI build matrix. Reviewed as design context under GPL-3.0; no code is copied. See [`docs/modules.md`](docs/modules.md).
|
|
271
|
+
- [`REAndroid/APKEditor`](https://github.com/REAndroid/APKEditor) and [`patrickfav/uber-apk-signer`](https://github.com/patrickfav/uber-apk-signer): split merge and APK signing tools.
|
|
272
|
+
- [ReVanced](https://revanced.app/): the patch ecosystem Morphe builds on; ReVanced-compatible patch bundles can be selected per app via `patches-source`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "morphe-builder"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Build verified Morphe-patched Android APKs and modules"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "Mikel Villota" }]
|
|
13
|
+
requires-python = ">=3.11,<3.14"
|
|
14
|
+
keywords = ["android", "apk", "morphe", "patcher", "revanced"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Operating System :: Microsoft :: Windows",
|
|
19
|
+
"Operating System :: POSIX :: Linux",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Build Tools",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"apkutils2==1.0.0",
|
|
28
|
+
# PyPI cannot encode reviewed VCS sources. Version 0.0.0 prevents pip from
|
|
29
|
+
# silently substituting the incompatible upstream gplaydl distribution.
|
|
30
|
+
"gplaydl==0.0.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Documentation = "https://github.com/Villoh/morphe-builder#readme"
|
|
35
|
+
Issues = "https://github.com/Villoh/morphe-builder/issues"
|
|
36
|
+
Repository = "https://github.com/Villoh/morphe-builder"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
morphe-builder = "morphe_builder:main"
|
|
40
|
+
|
|
41
|
+
[tool.uv]
|
|
42
|
+
# Quarantine new releases before dependency resolution admits them.
|
|
43
|
+
exclude-newer = "3 days"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
package-dir = { "" = "src" }
|
|
47
|
+
packages = ["morphe_builder"]
|
|
48
|
+
|
|
49
|
+
[tool.uv.sources]
|
|
50
|
+
gplaydl = { git = "https://github.com/Villoh/gplaydl.git", rev = "de7dfba240b09bc986523c1637ac672b0c295980" }
|