├── .dockerignore
├── .eslintrc.json
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.md
└── workflows
│ └── discord_ping_on_release.yml
├── .gitignore
├── .prettierrc.json
├── DEVELOPERS.md
├── DOCKERCOMPOSE.md
├── Dockerfile
├── LICENSE
├── README.md
├── android-interface.sh
├── docker-compose.yml
├── index.js
├── package-lock.json
├── package.json
├── public
├── about
│ └── index.html
├── apps.js
├── apps
│ └── index.html
├── colors.js
├── dependencies
│ └── index.html
├── devices
│ └── index.html
├── exited
│ └── index.html
├── failure
│ └── index.html
├── index.html
├── index.js
├── installer
│ └── index.html
├── patch
│ └── index.html
├── patches
│ └── index.html
├── settings.js
├── settings
│ └── index.html
├── styles
│ ├── about.css
│ ├── apps.css
│ ├── core.css
│ ├── dependencies.css
│ ├── failure.css
│ ├── fontawesome.css
│ ├── fonts
│ │ ├── Source Sans HW Bold.otf
│ │ └── Source Sans HW Regular.otf
│ ├── home.css
│ ├── patches.css
│ └── settings.css
├── versions
│ └── index.html
└── webfonts
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff2
│ ├── fa-solid-900.ttf
│ └── fa-solid-900.woff2
├── shell.nix
├── utils
├── AntiSplit.js
├── FileDownloader.js
├── PatchesParser.js
├── Settings.js
├── checkJDKAndADB.js
├── checkJDKAndAapt2.js
├── downloadApp.js
├── fetchWithUserAgent.js
├── getAppVersion.js
├── getDeviceArch.js
├── getDeviceID.js
├── mountReVanced.js
├── mountReVancedInstaller.js
├── promisifiedExec.js
└── uploadAPKFile.js
└── wsEvents
├── checkFileAlreadyExists.js
├── checkForUpdates.js
├── getApp.js
├── getAppVersion.js
├── getDevices.js
├── getPatches.js
├── getSettings.js
├── index.js
├── installReVanced.js
├── patchApp.js
├── resetPatchOptions.js
├── resetSettings.js
├── selectApp.js
├── selectAppVersion.js
├── selectPatches.js
├── setDevice.js
├── setSettings.js
└── updateFiles.js
/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es2021": true,
6 | "node": true
7 | },
8 | "extends": "eslint:recommended",
9 | "overrides": [],
10 | "parserOptions": {
11 | "ecmaVersion": "latest"
12 | },
13 | "rules": {}
14 | }
15 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **rvx-builder Version:** [e.g. v3.11.1]
24 |
25 | **Desktop (please complete the following information):**
26 |
27 | - OS: [e.g. Windows]
28 | - Version: [e.g. 10]
29 |
30 | **Additional context**
31 | Add any other context about the problem here.
32 |
--------------------------------------------------------------------------------
/.github/workflows/discord_ping_on_release.yml:
--------------------------------------------------------------------------------
1 | name: Ping Discord on release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | notify-discord:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: sarisia/actions-status-discord@v1
12 | if: always()
13 | id: webhook # set id to reference output payload later
14 | with:
15 | ack_no_webhook: true # suppress warning
16 | nodetail: true
17 | notimestamp: true
18 |
19 | username: ReVanced Extended
20 | content: "<@&1271198236350087283>"
21 | title: "RVX-Builder `${{ github.event.release.tag_name }}` has been released!"
22 | description: |
23 | Click [here](${{ github.event.release.html_url }}) to download it and read the changelog.
24 |
25 | - run: npm install axios
26 | - uses: actions/github-script@v7
27 | env:
28 | WEBHOOK_PAYLOAD: ${{ steps.webhook.outputs.payload }}
29 | WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
30 | with:
31 | script: |
32 | const axios = require("axios")
33 |
34 | const { WEBHOOK_PAYLOAD, WEBHOOK_URL } = process.env
35 |
36 | const payload = JSON.parse(WEBHOOK_PAYLOAD)
37 |
38 | // remove the color field to make it transparent
39 | delete payload.embeds[0].color
40 |
41 | // send to Discord
42 | axios.post(WEBHOOK_URL, payload)
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | ignore/
3 | revanced/
4 | rvx-builder-nodejs-macos
5 | rvx-builder-nodejs-linux
6 | rvx-builder-nodejs-win.exe
7 | excludedPatchesList.json
8 | includedPatchesList.json
9 | dist/
10 | revanced-resource-cache/
11 | index-old.js
12 | options.json
13 | settings.json
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "none"
4 | }
5 |
--------------------------------------------------------------------------------
/DEVELOPERS.md:
--------------------------------------------------------------------------------
1 | # Using the Builder (for developers)
2 |
3 | ## From source
4 |
5 | This is simple enough:
6 |
7 | ```bash
8 | git clone -b revanced-extended https://github.com/inotia00/rvx-builder.git --depth=1 --no-tags
9 | cd rvx-builder
10 | npm i
11 | node .
12 | ```
13 |
14 | Note that you need [git](https://git-scm.com/downloads) and [NodeJS >= 16](https://nodejs.org/en/) for this.
15 |
16 | ## Building a binary
17 |
18 | This is also simple:
19 |
20 | ```bash
21 | git clone -b revanced-extended https://github.com/inotia00/rvx-builder.git --depth=1 --no-tags
22 | cd rvx-builder
23 | npm i
24 | npx pkg -t linux-x64,macos-x64,win-x64 -C GZip .
25 | ```
26 |
--------------------------------------------------------------------------------
/DOCKERCOMPOSE.md:
--------------------------------------------------------------------------------
1 | ### These are the Windows 10/11 `docker-compose` instructions for beginners to run the rvx-builder in a clean docker container:
2 |
3 | **Please follow each step carefully and make sure you read everything.**
4 |
5 | 1. Install [`Git`](https://git-scm.com/) if you don't have it already. If you are not sure, install it.
6 |
7 | 2. Install and open [`Docker Desktop`](https://www.docker.com/products/docker-desktop/), it has to be running in the background for you to be able to run the builder container. Wait for it to load completely.
8 |
9 | If you're running Windows 11, you can open your PowerShell terminal and install both of the above requirements with this command:
10 | ```
11 | winget install --id=Git.Git -e && winget install --id=Docker.DockerDesktop -e --accept-package-agreements
12 | ```
13 |
14 | 3. After you install both I recommend creating a new empty folder and performing the next steps inside it for better organization.
15 |
16 | 4. Right click inside the newly created folder and select "Open in Terminal" or "Open PowerShell Here" in the context menu.
17 |
18 | 5. Now that you have a Terminal running, run:
19 | ```
20 | git clone -b revanced-extended https://github.com/inotia00/rvx-builder --depth=1 --no-tags
21 | ```
22 |
23 | 6. Then run this command to get from here to the rvx-builder directory:
24 | ```
25 | cd .\rvx-builder\
26 | ```
27 | *Or manually reopen the Terminal inside the newly created rvx-builder repository folder.*
28 |
29 | 7. To start building with **docker-compose** run:
30 | ```
31 | docker-compose build --no-cache
32 | ```
33 | *This can take a while, please wait for it to finish.*
34 |
35 | 8. After building, launch the container by running:
36 | ```
37 | docker-compose up -d
38 | ```
39 | In your browser open [localhost:8000](http://localhost:8000) to access the builder interface.
40 | Your built applications will be located in the **revanced** folder inside the the **rvx-builder** folder that is located in the folder you created in step 3.
41 |
42 | 9. When you are done building your applications, to stop the container you can run:
43 | ```
44 | docker-compose down
45 | ```
46 | Once that is done you can also stop Docker Desktop and close your Terminal window now.
47 |
48 |
49 | In the future when you're running the builder again, **after starting Docker Desktop**, you can open a Terminal inside the **rvx-builder** folder and start from step 7.
50 |
51 |
52 |
53 | #### Additonal information for advanced users:
54 | ##### Although it's recommended to build with the --no-cache flag, you don't necessarily have to unless you want to update the builder or just being safe, that way it will use the previous image to get you running the builder quickly.
55 |
56 | ##### If you run it in this fashion, to update the builder when you want to, open the Terminal inside the rvx-builder folder, do a `git pull` to be sure, and follow the `docker-compose` instructions to build again, and you really **have to** use the `--no-cache` flag this time.
57 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:lts-slim
2 |
3 | WORKDIR /app
4 |
5 | RUN apt-get --yes update && \
6 | apt-get --yes install git wget java-common libasound2 libxi6 libxtst6 xdg-utils libgtk2.0-0 libatk1.0-0 libpango1.0-0 libgdk-pixbuf2.0-0 libcairo2 libgl1-mesa-glx && \
7 | wget -O /app/zulu.deb https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-crac-jdk17.0.14-linux_amd64.deb && \
8 | yes | dpkg -i /app/zulu.deb && \
9 | rm /app/zulu.deb && \
10 | apt-get -f install
11 |
12 | RUN git clone -b revanced-extended https://github.com/inotia00/rvx-builder --depth=1 --no-tags
13 |
14 | WORKDIR /app/rvx-builder
15 |
16 | RUN npm install --omit=dev
17 |
18 | EXPOSE 8000
19 |
20 | CMD ["node", ".", "--no-open"]
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReVanced Extended Builder
2 |
3 | This project will allow you to download the APK of [supported](https://github.com/inotia00/revanced-patches?tab=readme-ov-file#-list-of-patches-in-this-repository) apps and build ReVanced Extended easily!
4 |
5 | ## How to use
6 |
7 | To use on PC, see [this document](https://github.com/inotia00/revanced-documentation/blob/main/docs/rvx-builder%20(pc).md).
8 |
9 | To use on Android (via Termux), see [this document](https://github.com/inotia00/revanced-documentation/blob/main/docs/rvx-builder%20(android).md).
10 |
11 | ## For developers
12 |
13 | For developers, see [this](https://github.com/inotia00/rvx-builder/blob/revanced-extended/DEVELOPERS.md)
14 |
15 | ## How to use (Docker)
16 |
17 | Required [docker](https://docs.docker.com/get-docker/) and [docker-compose (for \*nix cli)](https://docs.docker.com/compose/install/linux/) must be installed
18 |
19 | **Note:** If you're using Docker Desktop, `docker-compose` will be pre-installed.
20 |
21 | Clone the repository and `cd` into the directory `rvx-builder`
22 |
23 | ### Build using `docker-compose`
24 |
25 | ```bash
26 | docker-compose build --pull --no-cache
27 | ```
28 |
29 | This builds the Docker image (`--no-cache` is used to build the image from scratch; sometimes the cache might cause version conflicts).
30 |
31 | After building, launch the container (runs at `localhost:8000`):
32 |
33 | ```bash
34 | docker-compose up -d
35 | ```
36 |
37 | To stop the container:
38 |
39 | ```bash
40 | docker-compose down
41 | ```
42 |
43 | **Note: docker-compose uses docker-compose.yml so make sure you are in the same directory `rvx-builder`**
44 |
45 | To update to a newer version, stop the existing container if it is running, build the image and start it again.
46 |
47 | ### Build using only `docker`
48 |
49 | ```bash
50 | docker build . --pull -t --no-cache
51 | ```
52 |
53 | Run the newly built container:
54 |
55 | ```bash
56 | docker run -d --name -p 8000:8000 --restart unless-stopped -v ./revanced/:/app/rvx-builder/revanced/
57 | ```
58 |
59 | This launches the container on `http://localhost:8000`
60 |
61 | To stop the container:
62 |
63 | ```bash
64 | docker rm -f
65 | docker rmi -f
66 | ```
67 |
68 | To update to a newer version of Builder, stop the existing container if it is running, build the container start it again.
69 |
70 | In both the builds, a persistent storage is kept. All the builds are stored in `/rvx-builder/revanced/`.
71 |
--------------------------------------------------------------------------------
/android-interface.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | shopt -s extglob
4 |
5 | SCR_NAME_EXEC=$0
6 | SCR_NAME_EXEC_FP=$(realpath "$0")
7 | SCR_NAME=$(basename "$SCR_NAME_EXEC")
8 | SCR_NAME=${SCR_NAME%.*}
9 | RVB_DIR=$HOME/rvx-builder
10 |
11 | COLOR_OFF='\033[0m'
12 | COLOR_RED='\033[1;31m'
13 |
14 | help_info() {
15 | cat <> ../usr/etc/bash.bashrc
59 | echo "alias rvxre='./rvx-builder.sh reinstall && ./rvx-builder.sh run'" >> ../usr/etc/bash.bashrc
60 | echo "alias rvxup='./rvx-builder.sh update && ./rvx-builder.sh run'" >> ../usr/etc/bash.bashrc
61 | echo "alias opon='nano rvx-builder/options.json'" >> ../usr/etc/bash.bashrc
62 | }
63 |
64 | dload_and_install() {
65 | log "Downloading rvx-builder..."
66 | curl -sLo rvx-builder.zip https://github.com/inotia00/rvx-builder/archive/refs/heads/revanced-extended.zip
67 | log "Unzipping..."
68 | unzip -qqo rvx-builder.zip
69 | rm rvx-builder.zip
70 | mv rvx-builder-revanced-extended/{.[!.]*,*} .
71 | log "Installing packages..."
72 | npm install --omit=dev
73 | rmdir rvx-builder-revanced-extended
74 | [[ -z "$1" ]] && log "Done. Execute \`$SCR_NAME_EXEC run\` to launch the builder."
75 | }
76 |
77 | preflight() {
78 | setup_storage() {
79 | [[ ! -d "$HOME"/storage ]] && {
80 | log "You will now get a permission dialog to allow access to storage."
81 | log "This is needed in order to move the built APK (+ MicroG) to internal storage."
82 | sleep 5
83 | termux-setup-storage
84 | } || {
85 | log "Already gotten storage access."
86 | }
87 | }
88 |
89 | install_dependencies() {
90 | [[ -f "$RVB_DIR/settings.json" ]] && {
91 | log "Node.js and JDK already installed."
92 | return
93 | }
94 | log "Updating Termux and installing dependencies..."
95 | pkg update -y
96 | pkg install nodejs-lts openjdk-17 -y || {
97 | error "$COLOR_RED
98 | Failed to install Node.js and OpenJDK 17.
99 | Possible reasons (in the order of commonality):
100 | 1. Termux was downloaded from Play Store. Termux in Play Store is deprecated, and has packaging bugs. Please install it from F-Droid.
101 | 2. Mirrors are down at the moment. Try running \`termux-change-repo\`.
102 | 3. Internet connection is unstable.
103 | 4. Lack of free storage.$COLOR_OFF" n 2
104 | }
105 | }
106 |
107 | setup_storage
108 | install_dependencies
109 |
110 | [[ ! -d "$RVB_DIR" ]] && {
111 | set_alias
112 | log "rvx-builder not installed. Installing..."
113 | mkdir -p "$RVB_DIR"
114 | cd "$RVB_DIR"
115 | dload_and_install n
116 | } || {
117 | log "rvx-builder found."
118 | log "All checks done."
119 | }
120 | }
121 |
122 | run_builder() {
123 | preflight
124 | termux-wake-lock
125 | echo
126 | [[ "$1" == "--delete-cache" ]] || [[ "$1" == "--dc" ]] && {
127 | delete_cache
128 | }
129 | [[ "$1" == "--delete-cache-no-keystore" ]] || [[ "$1" == "--dcnk" ]] && {
130 | delete_cache_no_keystore
131 | }
132 | cd "$RVB_DIR"
133 | node .
134 | [[ "$1" == "--delete-cache-after" ]] || [[ "$1" == "--dca" ]] && {
135 | delete_cache
136 | }
137 | [[ "$1" == "--delete-cache-after-no-keystore" ]] || [[ "$1" == "--dcank" ]] && {
138 | delete_cache_no_keystore
139 | }
140 | termux-wake-unlock
141 | }
142 |
143 | delete_cache() {
144 | # Is this even called a cache?
145 | log "Deleting builder cache..."
146 | rm -rf "$RVB_DIR"/revanced
147 | }
148 |
149 | delete_cache_no_keystore() {
150 | log "Deleting builder cache preserving keystore..."
151 | mv "$RVB_DIR"/revanced/revanced.keystore "$HOME"/revanced.keystore
152 | rm -rf "$RVB_DIR"/revanced
153 | mkdir -p "$RVB_DIR"/revanced
154 | mv "$HOME"/revanced.keystore "$RVB_DIR"/revanced/revanced.keystore
155 | }
156 |
157 | reinstall_builder() {
158 | log "Deleting rvx-builder..."
159 | [[ "$1" != "--delete-keystore" ]] && {
160 | [[ -f "$RVB_DIR/revanced/revanced.keystore" ]] && {
161 | mv "$RVB_DIR"/revanced/revanced.keystore "$HOME"/revanced.keystore
162 | log "Preserving the keystore. If you do not want this, use the --delete-keystore flag."
163 | log "Execute \`$SCR_NAME_EXEC help\` for more info."
164 | }
165 | }
166 | rm -r "$RVB_DIR"
167 | mkdir -p "$RVB_DIR"
168 | [[ -f "$HOME/revanced.keystore" ]] && {
169 | log "Restoring the keystore..."
170 | mkdir -p "$RVB_DIR"/revanced
171 | mv "$HOME"/revanced.keystore "$RVB_DIR"/revanced/revanced.keystore
172 | }
173 | log "Reinstalling..."
174 | cd "$RVB_DIR"
175 | dload_and_install
176 | }
177 |
178 | update_builder() {
179 | log "Backing up some stuff..."
180 | [[ -d "$RVB_DIR/revanced" ]] && {
181 | mkdir -p "$HOME"/revanced_backup
182 | mv "$RVB_DIR"/revanced/* "$HOME"/revanced_backup
183 | }
184 | [[ -f "$RVB_DIR/settings.json" ]] && {
185 | mv "$RVB_DIR"/settings.json "$HOME"/settings.json
186 | }
187 | log "Deleting rvx-builder..."
188 | rm -r "$RVB_DIR"
189 | log "Restoring the backup..."
190 | mkdir -p "$RVB_DIR"
191 | [[ -d "$HOME/revanced_backup" ]] && {
192 | mkdir -p "$RVB_DIR"/revanced
193 | mv "$HOME"/revanced_backup/* "$RVB_DIR"/revanced
194 | }
195 | [[ -f "$HOME/settings.json" ]] && {
196 | mv "$HOME"/settings.json "$RVB_DIR"/settings.json
197 | }
198 | log "Updating rvx-builder..."
199 | cd "$RVB_DIR"
200 | dload_and_install n
201 | run_self_update
202 | }
203 |
204 | run_self_update() {
205 | log "Performing self-update..."
206 |
207 | # Download new version
208 | log "Downloading latest version..."
209 | ! curl -sLo "$SCR_NAME_EXEC_FP".tmp https://raw.githubusercontent.com/inotia00/rvx-builder/revanced-extended/android-interface.sh && {
210 | log "Failed: Error while trying to download new version!"
211 | error "File requested: https://raw.githubusercontent.com/inotia00/rvx-builder/revanced-extended/android-interface.sh" n
212 | } || log "Done."
213 |
214 | # Copy over modes from old version
215 | OCTAL_MODE=$(stat -c '%a' "$SCR_NAME_EXEC_FP")
216 | ! chmod "$OCTAL_MODE" "$SCR_NAME_EXEC_FP.tmp" && error "Failed: Error while trying to set mode on $SCR_NAME_EXEC.tmp." n
217 |
218 | # Spawn update script
219 | cat > updateScript.sh << EOF
220 | #!/bin/bash
221 |
222 | # Overwrite old file with new
223 | mv "$SCR_NAME_EXEC_FP.tmp" "$SCR_NAME_EXEC_FP" && {
224 | echo -e "[$SCR_NAME] Done. Execute '$SCR_NAME_EXEC run' to launch the builder."
225 | rm \$0
226 | } || {
227 | echo "[$SCR_NAME] Failed!"
228 | }
229 | EOF
230 |
231 | log "Running update process..."
232 | exec /bin/bash updateScript.sh
233 | }
234 |
235 | main() {
236 | if [[ -z "$@" ]]; then
237 | run_builder
238 | elif [[ $# -gt 2 ]]; then
239 | error "2 optional arguments acceptable, got $#."
240 | else
241 | case $1 in
242 | run)
243 | run_builder "$2"
244 | ;;
245 | reinstall)
246 | reinstall_builder "$2"
247 | ;;
248 | update)
249 | update_builder
250 | ;;
251 | help)
252 | help_info
253 | ;;
254 | *)
255 | error "Invalid argument(s): $@."
256 | ;;
257 | esac
258 | fi
259 | }
260 |
261 | main $@
262 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | rvx-builder:
4 | container_name: rvx-builder
5 | restart: unless-stopped
6 | build:
7 | context: ./
8 | dockerfile: Dockerfile
9 | volumes:
10 | - ./revanced/:/app/rvx-builder/revanced/
11 | ports:
12 | - 8000:8000
13 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const { createServer } = require('node:http');
2 | const { join } = require('node:path');
3 |
4 | const exec = require('./utils/promisifiedExec.js');
5 | const uploadAPKFile = require('./utils/uploadAPKFile.js');
6 |
7 | const Express = require('express');
8 | const fileUpload = require('express-fileupload');
9 | const { WebSocketServer } = require('ws');
10 | const open_ = require('open');
11 | const pf = require('portfinder');
12 |
13 | const fkill = require('fkill');
14 |
15 | const {
16 | checkFileAlreadyExists,
17 | checkForUpdates,
18 | fetchWithUserAgent,
19 | getApp,
20 | getAppVersion,
21 | getDevices,
22 | getPatches,
23 | getSettings,
24 | installReVanced,
25 | patchApp,
26 | resetPatchOptions,
27 | resetSettings,
28 | selectApp,
29 | selectAppVersion,
30 | selectPatches,
31 | setDevice,
32 | setSettings,
33 | updateFiles
34 | } = require('./wsEvents/index.js');
35 |
36 | const app = Express();
37 | const server = createServer(app);
38 | const wsServer = new WebSocketServer({ server });
39 | const wsClients = [];
40 |
41 | app.use(fileUpload());
42 | app.use(Express.static(join(__dirname, 'public')));
43 | app.get('/revanced.apk', (_, res) => {
44 | const file = join(process.cwd(), 'revanced', global.outputName);
45 |
46 | res.download(file);
47 | });
48 |
49 | app.post('/uploadApk', (req, res) => {
50 | req.socket.setTimeout(60000 * 60);
51 | req.setTimeout(60000 * 60);
52 | uploadAPKFile(req, res, wsClients);
53 | });
54 |
55 | /**
56 | * @param {number} port
57 | */
58 | const open = async (port) => {
59 | if (process.platform === 'android')
60 | await exec(`termux-open-url http://localhost:${port}`);
61 | else await open_(`http://localhost:${port}`);
62 | };
63 |
64 | /**
65 | * @param {string} msg
66 | */
67 | const log = (msg, newline = true, tag = true) => {
68 | if (newline) console.log(`${tag ? '[builder] ' : ''}${msg}`);
69 | else process.stdout.write(`${tag ? '[builder] ' : ''}${msg} `);
70 | };
71 |
72 | /**
73 | * @param {number} port
74 | */
75 | const listen = (port) => {
76 | server.listen(port, async () => {
77 | if (process.argv.includes('--no-open'))
78 | log(`The webserver is now running at http://localhost:${port}`);
79 | else {
80 | log('The webserver is now running!');
81 |
82 | try {
83 | log('Opening the app in the default browser...', false);
84 |
85 | await open(port);
86 |
87 | log('Done, check if a browser window has opened', true, false);
88 | } catch {
89 | log(
90 | `Failed. Open up http://localhost:${port} manually in your browser.`,
91 | true,
92 | false
93 | );
94 | }
95 | }
96 | });
97 | };
98 |
99 | /**
100 | * @param {import('http').Server} svr
101 | */
102 | const cleanExit = async (svr) => {
103 | log('Killing any dangling processes...', false);
104 |
105 | try {
106 | await fkill(['adb', 'java', 'aapt2'], {
107 | forceAfterTimeout: 3000,
108 | tree: true,
109 | silent: true
110 | });
111 | log('Done.', true, false);
112 | } catch (error) {
113 | log('Failed.', true, false);
114 | log(
115 | 'If there are certain processes still running, you can kill them manually'
116 | );
117 | log(error?.stack, true, false);
118 | }
119 |
120 | log('Stopping the server...', false);
121 |
122 | svr.close(() => log('Done', true, false));
123 | setTimeout(() => process.exit(0), 2_500);
124 | };
125 |
126 | pf.getPortPromise()
127 | .then((freePort) => {
128 | log(`Listening at port ${freePort}`);
129 | listen(freePort);
130 | })
131 | .catch((err) => {
132 | log(`Unable to determine free ports.\nReason: ${err}`);
133 | log('Falling back to 8080.');
134 | listen(8080);
135 | });
136 |
137 | process.on('uncaughtException', (reason) => {
138 | log(`An error occured.\n${reason.stack}`);
139 | log(
140 | 'Please report this bug here: https://github.com/inotia00/rvx-builder/issues.'
141 | );
142 | });
143 |
144 | process.on('unhandledRejection', (reason) => {
145 | log(`An error occured.\n${reason.stack}`);
146 | log(
147 | 'Please report this bug here: https://github.com/inotia00/rvx-builder/issues.'
148 | );
149 |
150 | for (const wsClient of wsClients) {
151 | wsClient.send(
152 | JSON.stringify({
153 | event: 'error',
154 | error: encodeURIComponent(
155 | `An error occured:\n${reason.stack}\nPlease report this bug here: https://github.com/inotia00/rvx-builder/issues.`
156 | )
157 | })
158 | );
159 | }
160 | });
161 |
162 | process.on('SIGTERM', () => cleanExit(server));
163 | process.on('SIGINT', () => cleanExit(server));
164 |
165 | // The websocket server
166 | wsServer.on('connection', (ws) => {
167 | wsClients.push(ws);
168 | ws.on('message', async (msg) => {
169 | /** @type {Record} */
170 | const message = JSON.parse(msg);
171 |
172 | // Theres no file handler, soo...
173 |
174 | switch (message.event) {
175 | case 'checkFileAlreadyExists':
176 | checkFileAlreadyExists(ws);
177 | break;
178 | case 'checkForUpdates':
179 | await checkForUpdates(ws);
180 | break;
181 | case 'fetchWithUserAgent':
182 | await fetchWithUserAgent(ws);
183 | break;
184 | case 'getAppList':
185 | await getApp(ws);
186 | break;
187 | case 'getAppVersion':
188 | await getAppVersion(ws, message);
189 | break;
190 | case 'getDevices':
191 | await getDevices(ws);
192 | break;
193 | case 'getPatches':
194 | await getPatches(ws, message);
195 | break;
196 | case 'getSettings':
197 | await getSettings(ws);
198 | break;
199 | case 'installReVanced':
200 | await installReVanced(ws);
201 | break;
202 | case 'patchApp':
203 | await patchApp(ws, message);
204 | break;
205 | case 'resetPatchOptions':
206 | await resetPatchOptions(ws);
207 | break;
208 | case 'resetSettings':
209 | await resetSettings(ws);
210 | break;
211 | case 'selectApp':
212 | selectApp(message);
213 | break;
214 | case 'selectAppVersion':
215 | await selectAppVersion(message, ws);
216 | break;
217 | case 'selectPatches':
218 | selectPatches(message);
219 | break;
220 | case 'setDevice':
221 | setDevice(message);
222 | break;
223 | case 'setSettings':
224 | await setSettings(message);
225 | break;
226 | case 'updateFiles':
227 | await updateFiles(ws);
228 | break;
229 | case 'exit':
230 | process.kill(process.pid, 'SIGTERM');
231 | }
232 | });
233 | });
234 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rvx-builder",
3 | "version": "1.0.0",
4 | "description": "",
5 | "bin": "index.js",
6 | "main": "index.js",
7 | "type": "commonjs",
8 | "pkg": {
9 | "assets": [
10 | "public/**/*"
11 | ]
12 | },
13 | "scripts": {
14 | "start": "node .",
15 | "fmt": "prettier --write . && eslint --fix ."
16 | },
17 | "keywords": [],
18 | "author": "",
19 | "license": "ISC",
20 | "dependencies": {
21 | "app-info-parser": "^1.1.6",
22 | "cheerio": "^1.0.0",
23 | "express": "^4.21.2",
24 | "express-fileupload": "^1.5.1",
25 | "fkill": "^7.2.1",
26 | "node-fetch": "^2.7.0",
27 | "node-fetch-progress": "^1.0.2",
28 | "open": "^8.4.2",
29 | "portfinder": "^1.0.32",
30 | "prettier": "^3.4.2",
31 | "semver": "^7.6.0",
32 | "tar": "^6.2.1",
33 | "ws": "^8.18.0"
34 | },
35 | "devDependencies": {
36 | "eslint": "^9.16.0"
37 | },
38 | "engines": {
39 | "node": ">=18"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/public/about/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | About
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
About
19 |
20 |
21 |
22 |
ReVanced Builder
23 |
24 | ReVanced Builder is a simple tool built with NodeJS to patch
25 | ReVanced-supported applications. It ships with a beginner-friendly
26 | UI so that everyone can use it easily. Check out
27 | GitHub Readme
32 | for more information.
33 |
19 | Select the device(s)
20 | you want to install ReVanced to
21 |
22 | ReVanced Builder has detected that you have more than one device
24 | plugged in. Please select the device(s) that you want to
25 | install ReVanced.
27 |
28 |
520 | YouTube Music APKs only have specific architecture APKs.
521 | If you don't know which one to choose, either look at your devices architecture using CPU-Z or select Arm64.`;
522 | document.getElementById('versions').innerHTML = `
523 |
26 | Customize the Accent color of the builder. Use the palette
27 | option to use a custom color.
28 |
29 |
30 |
33 |
36 |
39 |
42 |
45 | 🎨
52 |
53 |
54 |
55 |
56 |
57 | Pure Black Theme
58 |
59 |
60 | The pure black theme uses a black background and helps reduce
61 | battery usage on AMOLED devices or maybe you can just turn it on
62 | when the dark theme is not enough.
63 |
64 |
71 |
72 |
73 |
74 | Automatically
75 | proceed to next page
76 |
77 |
78 |
79 | This helps save time by proceeding automatically to the next
80 | page on downloading pages.
Caution: It may break your back
81 | button.
82 |
83 |
90 |
91 |
92 |
93 | Use pre-release
94 |
95 |
96 |
97 | Use the pre-release versions of patches and integrations if ahead of the stable version.
98 |
Caution: Use pre-release is for development purposes and may cause unexpected issues.
99 |
100 |
107 |
108 |
109 |
110 | Remove unused library
111 |
112 |
113 |
114 | Leave only libraries that match the device's architecture.
115 |
Caution: Available only on Android (termux).
116 |
117 |
124 |
125 |
126 |
127 |
128 | Show universal patches
129 |
130 |
131 |
132 | Display all universal patches.
133 |
134 |
141 |
142 |
143 |
144 |
145 | Reset settings
146 |
147 |
148 |
149 | Resets the source and selected patch list.
150 |
Try this if the patch is excluded even though you included it.
151 |