mirror of
https://github.com/SinTan1729/ReVancedBuilder.git
synced 2025-04-19 16:10:00 -05:00
fix: Warnings and errors reported by ruff
This commit is contained in:
parent
ad125bfb7b
commit
ee3eef71aa
5 changed files with 256 additions and 230 deletions
101
src/ReVancedBuilder/APKPure_dl.py
Normal file → Executable file
101
src/ReVancedBuilder/APKPure_dl.py
Normal file → Executable file
|
@ -5,61 +5,62 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from packaging.version import Version
|
|
||||||
import cloudscraper as scraper
|
import cloudscraper as scraper
|
||||||
from bs4 import BeautifulSoup as bs
|
from bs4 import BeautifulSoup as bs
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
from ReVancedBuilder.Cleanup import err_exit
|
from ReVancedBuilder.Cleanup import err_exit
|
||||||
|
|
||||||
# Determine the best version available to download
|
# Determine the best version available to download
|
||||||
|
|
||||||
|
|
||||||
def apkpure_best_match(version, soup):
|
def apkpure_best_match(version, soup, appstate, apk):
|
||||||
try:
|
try:
|
||||||
vers_list_str = [x['data-dt-version'] for x in soup.css.select(f"a[data-dt-apkid^=\"b/APK/\"]")]
|
vers_list_str = [
|
||||||
except:
|
x["data-dt-version"] for x in soup.css.select('a[data-dt-apkid^="b/APK/"]')
|
||||||
err_exit(
|
]
|
||||||
f" There was some error getting list of versions of {apk}...", appstate)
|
except Exception as ex:
|
||||||
|
err_exit(f" There was some error getting list of versions of {apk}: {ex}", appstate)
|
||||||
|
|
||||||
vers_list = map(lambda x: Version(x), vers_list_str)
|
vers_list = map(lambda x: Version(x), vers_list_str)
|
||||||
|
|
||||||
if version != '0':
|
if version != "0":
|
||||||
vers_list = filter(lambda x: x <= Version(version), vers_list)
|
vers_list = filter(lambda x: x <= Version(version), vers_list)
|
||||||
|
|
||||||
max_ver = max(vers_list)
|
max_ver = max(vers_list)
|
||||||
return next(filter(lambda x: Version(x) == max_ver, vers_list_str))
|
return next(filter(lambda x: Version(x) == max_ver, vers_list_str))
|
||||||
|
|
||||||
|
|
||||||
# Download an apk from apkpure.net
|
# Download an apk from apkpure.net
|
||||||
|
|
||||||
|
|
||||||
def apkpure_dl(apk, appname, version, hard_version, session, present_vers, flag):
|
def apkpure_dl(apk, appname, version, hard_version, session, present_vers, flag, appstate):
|
||||||
res = session.get(f"https://apkpure.com/{appname}/{apk}/versions")
|
res = session.get(f"https://apkpure.com/{appname}/{apk}/versions")
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
soup = bs(res.text, 'html.parser')
|
soup = bs(res.text, "html.parser")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if present_vers[apk] == version and flag != 'force' and os.path.isfile(apk+'.apk'):
|
if present_vers[apk] == version and flag != "force" and os.path.isfile(apk + ".apk"):
|
||||||
print(
|
print(f"Recommended version {version} of {apk} is already present.")
|
||||||
f"Recommended version {version} of {apk} is already present.")
|
|
||||||
return
|
return
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not hard_version:
|
if not hard_version:
|
||||||
apkpure_version = apkpure_best_match(version, soup)
|
apkpure_version = apkpure_best_match(version, soup, appstate, apk)
|
||||||
if version not in [apkpure_version, '0']:
|
if version not in [apkpure_version, "0"]:
|
||||||
print(
|
print(
|
||||||
f"Required version {version} not found in APKPure, choosing version {apkpure_version} instead.")
|
f"Required version {version} not found in APKPure, choosing version {apkpure_version} instead."
|
||||||
|
)
|
||||||
version = apkpure_version
|
version = apkpure_version
|
||||||
try:
|
try:
|
||||||
if present_vers[apk] == version and flag != 'force' and os.path.isfile(apk+'.apk'):
|
if present_vers[apk] == version and flag != "force" and os.path.isfile(apk + ".apk"):
|
||||||
print(
|
print(f"Recommended version {version} of {apk} is already present.")
|
||||||
f"Recommended version {version} of {apk} is already present.")
|
|
||||||
return
|
return
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if flag == 'checkonly' and present_vers[apk] != version:
|
if flag == "checkonly" and present_vers[apk] != version:
|
||||||
print(f"{apk} has an update ({present_vers[apk]} -> {version})")
|
print(f"{apk} has an update ({present_vers[apk]} -> {version})")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -67,16 +68,15 @@ def apkpure_dl(apk, appname, version, hard_version, session, present_vers, flag)
|
||||||
|
|
||||||
# Get the version code
|
# Get the version code
|
||||||
try:
|
try:
|
||||||
ver_code = soup.css.select(
|
ver_code = soup.css.select(f'a[data-dt-version="{version}"][data-dt-apkid^="b/APK/"]')[0][
|
||||||
f"a[data-dt-version=\"{version}\"][data-dt-apkid^=\"b/APK/\"]")[0]['data-dt-versioncode']
|
"data-dt-versioncode"
|
||||||
except:
|
]
|
||||||
err_exit(
|
except Exception as ex:
|
||||||
f" There was some error while downloading {apk}...", appname)
|
err_exit(f" There was some error while downloading {apk}: {ex}", appstate)
|
||||||
|
|
||||||
res = session.get(
|
res = session.get(f"https://d.apkpure.com/b/APK/{apk}?versionCode={ver_code}", stream=True)
|
||||||
f"https://d.apkpure.com/b/APK/{apk}?versionCode={ver_code}", stream=True)
|
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
with open(apk+'.apk', 'wb') as f:
|
with open(apk + ".apk", "wb") as f:
|
||||||
for chunk in res.iter_content(chunk_size=8192):
|
for chunk in res.iter_content(chunk_size=8192):
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
print(" Done!")
|
print(" Done!")
|
||||||
|
@ -84,11 +84,11 @@ def apkpure_dl(apk, appname, version, hard_version, session, present_vers, flag)
|
||||||
|
|
||||||
# Download apk files, if needed
|
# Download apk files, if needed
|
||||||
def get_apks(appstate):
|
def get_apks(appstate):
|
||||||
present_vers = appstate['present_vers']
|
present_vers = appstate["present_vers"]
|
||||||
build_config = appstate['build_config']
|
build_config = appstate["build_config"]
|
||||||
flag = appstate['flag']
|
flag = appstate["flag"]
|
||||||
|
|
||||||
print('Downloading required apk files from APKPure...')
|
print("Downloading required apk files from APKPure...")
|
||||||
|
|
||||||
# Create a cloudscraper session
|
# Create a cloudscraper session
|
||||||
session = scraper.create_scraper()
|
session = scraper.create_scraper()
|
||||||
|
@ -96,51 +96,60 @@ def get_apks(appstate):
|
||||||
# Get latest patches using the ReVanced API
|
# Get latest patches using the ReVanced API
|
||||||
try:
|
try:
|
||||||
# Get the first result
|
# Get the first result
|
||||||
patches = session.get('https://api.revanced.app/v4/patches/list').json()
|
patches = session.get("https://api.revanced.app/v4/patches/list").json()
|
||||||
except session.exceptions.RequestException as e:
|
except session.exceptions.RequestException as e:
|
||||||
err_exit(f"Error fetching patches, {e}", appstate)
|
err_exit(f"Error fetching patches, {e}", appstate)
|
||||||
|
|
||||||
for app in build_config:
|
for app in build_config:
|
||||||
# Check if we need to build an app
|
# Check if we need to build an app
|
||||||
if not build_config[app].getboolean('build'):
|
if not build_config[app].getboolean("build"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
apk = build_config[app]['apk']
|
apk = build_config[app]["apk"]
|
||||||
pretty_name = build_config[app]['pretty_name']
|
pretty_name = build_config[app]["pretty_name"]
|
||||||
apkpure_appname = build_config[app]['apkpure_appname']
|
apkpure_appname = build_config[app]["apkpure_appname"]
|
||||||
except:
|
except Exception as ex:
|
||||||
err_exit(f"Invalid config for {app} in build_config!", appstate)
|
err_exit(f"Invalid config for {app} in build_config!: {ex}", appstate)
|
||||||
|
|
||||||
print(f"Checking {pretty_name}...")
|
print(f"Checking {pretty_name}...")
|
||||||
try:
|
try:
|
||||||
required_ver = build_config[app]['version']
|
required_ver = build_config[app]["version"]
|
||||||
hard_version = True
|
hard_version = True
|
||||||
print(f"Using version {required_ver} of {apk} from build_config.")
|
print(f"Using version {required_ver} of {apk} from build_config.")
|
||||||
except:
|
except Exception as ex:
|
||||||
|
print(f"Dealing with exception: {ex}")
|
||||||
hard_version = False
|
hard_version = False
|
||||||
compatible_vers = []
|
compatible_vers = []
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
try:
|
try:
|
||||||
compatible_vers.append(patch['compatiblePackages'][apk][-1])
|
compatible_vers.append(patch["compatiblePackages"][apk][-1])
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not compatible_vers:
|
if not compatible_vers:
|
||||||
required_ver = Version('0')
|
required_ver = Version("0")
|
||||||
else:
|
else:
|
||||||
required_ver = min(map(lambda x: Version(x), compatible_vers))
|
required_ver = min(map(lambda x: Version(x), compatible_vers))
|
||||||
required_ver = next(filter(lambda x: Version(x) == required_ver, compatible_vers))
|
required_ver = next(filter(lambda x: Version(x) == required_ver, compatible_vers))
|
||||||
|
|
||||||
print(f"Chosen required version of {apk} is {required_ver}.")
|
print(f"Chosen required version of {apk} is {required_ver}.")
|
||||||
|
|
||||||
if apk in appstate['present_vers'] and appstate['present_vers'][apk] == required_ver:
|
if apk in appstate["present_vers"] and appstate["present_vers"][apk] == required_ver:
|
||||||
print("It's already present on disk, so skipping download.")
|
print("It's already present on disk, so skipping download.")
|
||||||
else:
|
else:
|
||||||
apkpure_dl(apk, apkpure_appname, required_ver,
|
apkpure_dl(
|
||||||
hard_version, session, present_vers, flag)
|
apk,
|
||||||
|
apkpure_appname,
|
||||||
|
required_ver,
|
||||||
|
hard_version,
|
||||||
|
session,
|
||||||
|
present_vers,
|
||||||
|
flag,
|
||||||
|
appstate,
|
||||||
|
)
|
||||||
|
|
||||||
present_vers.update({apk: required_ver})
|
present_vers.update({apk: required_ver})
|
||||||
|
|
||||||
appstate['present_vers'] = present_vers
|
appstate["present_vers"] = present_vers
|
||||||
return appstate
|
return appstate
|
||||||
|
|
28
src/ReVancedBuilder/Cleanup.py
Normal file → Executable file
28
src/ReVancedBuilder/Cleanup.py
Normal file → Executable file
|
@ -13,28 +13,28 @@ from ReVancedBuilder.Notifications import send_notif
|
||||||
|
|
||||||
|
|
||||||
def move_apps(appstate):
|
def move_apps(appstate):
|
||||||
build_config = appstate['build_config']
|
build_config = appstate["build_config"]
|
||||||
print = appstate['logger'].info
|
print = appstate["logger"].info
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.mkdir('archive')
|
os.mkdir("archive")
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for app in build_config:
|
for app in build_config:
|
||||||
if not build_config[app].getboolean('build'):
|
if not build_config[app].getboolean("build"):
|
||||||
continue
|
continue
|
||||||
name = build_config[app]['output_name']
|
name = build_config[app]["output_name"]
|
||||||
final_name = f"{name}_{appstate['timestamp']}.apk"
|
final_name = f"{name}_{appstate['timestamp']}.apk"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.rename(name+'.apk', 'archive/'+final_name)
|
os.rename(name + ".apk", "archive/" + final_name)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
# sys.exit('There was an error moving the final apk files!')
|
# sys.exit('There was an error moving the final apk files!')
|
||||||
|
|
||||||
# Do some cleanup, keep only the last 3 build's worth of files and a week worth of logs
|
# Do some cleanup, keep only the last 3 build's worth of files and a week worth of logs
|
||||||
with os.scandir('archive') as dir:
|
with os.scandir("archive") as dir:
|
||||||
files = []
|
files = []
|
||||||
for f in dir:
|
for f in dir:
|
||||||
if name in f.name:
|
if name in f.name:
|
||||||
|
@ -43,10 +43,10 @@ def move_apps(appstate):
|
||||||
files.reverse()
|
files.reverse()
|
||||||
for f in files[3:]:
|
for f in files[3:]:
|
||||||
os.remove(f)
|
os.remove(f)
|
||||||
print('Deleted old build '+f.name)
|
print("Deleted old build " + f.name)
|
||||||
|
|
||||||
# Delete logs older than 7 days
|
# Delete logs older than 7 days
|
||||||
with os.scandir('logs') as dir:
|
with os.scandir("logs") as dir:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
for f in dir:
|
for f in dir:
|
||||||
if f.stat().st_ctime < now - 7 * 86400:
|
if f.stat().st_ctime < now - 7 * 86400:
|
||||||
|
@ -54,18 +54,18 @@ def move_apps(appstate):
|
||||||
|
|
||||||
|
|
||||||
def err_exit(msg, appstate, code=1):
|
def err_exit(msg, appstate, code=1):
|
||||||
print = appstate['logger'].info
|
print = appstate["logger"].info
|
||||||
|
|
||||||
try:
|
try:
|
||||||
appstate['notification_config']
|
appstate["notification_config"]
|
||||||
if appstate['flag'] != 'checkonly':
|
if appstate["flag"] != "checkonly":
|
||||||
send_notif(appstate, error=True)
|
send_notif(appstate, error=True)
|
||||||
except:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
print(f"ERROR: {msg}")
|
print(f"ERROR: {msg}")
|
||||||
|
|
||||||
# Delete the lockfile
|
# Delete the lockfile
|
||||||
os.remove('lockfile')
|
os.remove("lockfile")
|
||||||
sys.exit(code)
|
sys.exit(code)
|
||||||
|
|
56
src/ReVancedBuilder/JAVABuilder.py
Normal file → Executable file
56
src/ReVancedBuilder/JAVABuilder.py
Normal file → Executable file
|
@ -3,9 +3,9 @@
|
||||||
# SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com>
|
# SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-3.0-only
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
import os
|
|
||||||
import configparser as cp
|
import configparser as cp
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from ReVancedBuilder.Cleanup import err_exit
|
from ReVancedBuilder.Cleanup import err_exit
|
||||||
|
@ -14,33 +14,33 @@ from ReVancedBuilder.Cleanup import err_exit
|
||||||
|
|
||||||
|
|
||||||
def build_apps(appstate):
|
def build_apps(appstate):
|
||||||
build_config = appstate['build_config']
|
build_config = appstate["build_config"]
|
||||||
flag = appstate['flag']
|
flag = appstate["flag"]
|
||||||
print = appstate['logger'].info
|
print = appstate["logger"].info
|
||||||
|
|
||||||
chosen_patches = cp.ConfigParser()
|
chosen_patches = cp.ConfigParser()
|
||||||
chosen_patches.read('chosen_patches')
|
chosen_patches.read("chosen_patches")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
included_patches = json.loads(chosen_patches['patches']['included'])
|
included_patches = json.loads(chosen_patches["patches"]["included"])
|
||||||
except:
|
except (KeyError, ValueError):
|
||||||
included_patches = []
|
included_patches = []
|
||||||
try:
|
try:
|
||||||
excluded_patches = json.loads(chosen_patches['patches']['excluded'])
|
excluded_patches = json.loads(chosen_patches["patches"]["excluded"])
|
||||||
except Exception as e:
|
except (KeyError, ValueError):
|
||||||
excluded_patches = []
|
excluded_patches = []
|
||||||
|
|
||||||
for app in build_config:
|
for app in build_config:
|
||||||
# Check if we need to build an app
|
# Check if we need to build an app
|
||||||
if not build_config[app].getboolean('build'):
|
if not build_config[app].getboolean("build"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Build the command to be run
|
# Build the command to be run
|
||||||
cmd = 'java -jar revanced-cli.jar patch -p revanced-patches.rvp'
|
cmd = "java -jar revanced-cli.jar patch -p revanced-patches.rvp"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
root = build_config[app].getboolean('root')
|
root = build_config[app].getboolean("root")
|
||||||
except:
|
except cp.Error:
|
||||||
root = False
|
root = False
|
||||||
|
|
||||||
if root:
|
if root:
|
||||||
|
@ -51,21 +51,21 @@ def build_apps(appstate):
|
||||||
for item in excluded_patches:
|
for item in excluded_patches:
|
||||||
cmd += f" -e {item}"
|
cmd += f" -e {item}"
|
||||||
|
|
||||||
if flag == 'experimental':
|
if flag == "experimental":
|
||||||
cmd += ' --experimental'
|
cmd += " --experimental"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
keystore = build_config[app]['keystore']
|
keystore = build_config[app]["keystore"]
|
||||||
if not root:
|
if not root:
|
||||||
cmd += f" --keystore {keystore} --keystore-entry-alias=alias --keystore-entry-password=ReVanced --keystore-password=ReVanced"
|
cmd += f" --keystore {keystore} --keystore-entry-alias=alias --keystore-entry-password=ReVanced --keystore-password=ReVanced"
|
||||||
except:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
apk = build_config[app]['apk']
|
apk = build_config[app]["apk"]
|
||||||
pretty_name = build_config[app]['pretty_name']
|
pretty_name = build_config[app]["pretty_name"]
|
||||||
output_name = build_config[app]['output_name']
|
output_name = build_config[app]["output_name"]
|
||||||
except:
|
except KeyError:
|
||||||
err_exit(f"Invalid config for {app} in build_config!", appstate)
|
err_exit(f"Invalid config for {app} in build_config!", appstate)
|
||||||
|
|
||||||
cmd += f" -o {output_name}.apk {apk}.apk"
|
cmd += f" -o {output_name}.apk {apk}.apk"
|
||||||
|
@ -76,17 +76,17 @@ def build_apps(appstate):
|
||||||
print(f"Building {pretty_name} (nonroot) using '{cmd}'")
|
print(f"Building {pretty_name} (nonroot) using '{cmd}'")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with subprocess.Popen(cmd, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout as output:
|
with subprocess.Popen(
|
||||||
|
cmd, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||||
|
).stdout as output:
|
||||||
for line in output:
|
for line in output:
|
||||||
line_utf = line.decode('utf-8').strip('\n')
|
line_utf = line.decode("utf-8").strip("\n")
|
||||||
if line_utf:
|
if line_utf:
|
||||||
print(line_utf)
|
print(line_utf)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_exit(
|
err_exit(f"There was an error while building {pretty_name}!\n{e}", appstate)
|
||||||
f"There was an error while building {pretty_name}!\n{e}", appstate)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.rename(output_name+'.apk', output_name+'.apk')
|
os.rename(output_name + ".apk", output_name + ".apk")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
err_exit(
|
err_exit(f"There was an error while building {pretty_name}!", appstate)
|
||||||
f"There was an error while building {pretty_name}!", appstate)
|
|
||||||
|
|
110
src/ReVancedBuilder/Notifications.py
Normal file → Executable file
110
src/ReVancedBuilder/Notifications.py
Normal file → Executable file
|
@ -5,97 +5,99 @@
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import requests as req
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
import requests as req
|
||||||
|
|
||||||
|
|
||||||
def send_notif(appstate, error=False):
|
def send_notif(appstate, error=False):
|
||||||
print = appstate['logger'].info
|
print = appstate["logger"].info
|
||||||
timestamp = appstate['timestamp']
|
timestamp = appstate["timestamp"]
|
||||||
|
|
||||||
if error:
|
if error:
|
||||||
msg = f"There was an error during build! Please check the logs.\nTimestamp: {timestamp}"
|
msg = f"There was an error during build! Please check the logs.\nTimestamp: {timestamp}"
|
||||||
else:
|
else:
|
||||||
notification_config = appstate['notification_config']
|
build_config = appstate["build_config"]
|
||||||
build_config = appstate['build_config']
|
present_vers = appstate["present_vers"]
|
||||||
present_vers = appstate['present_vers']
|
|
||||||
flag = appstate['flag']
|
|
||||||
|
|
||||||
msg = json.dumps(present_vers, indent=0)
|
msg = json.dumps(present_vers, indent=0)
|
||||||
msg = re.sub('("|\{|\}|,)', '', msg).strip('\n')
|
msg = re.sub('("|\{|\}|,)', "", msg).strip("\n")
|
||||||
|
|
||||||
msg = msg.replace('revanced-', 'ReVanced ')
|
msg = msg.replace("revanced-", "ReVanced ")
|
||||||
msg = msg.replace('cli', 'CLI')
|
msg = msg.replace("cli", "CLI")
|
||||||
msg = msg.replace('integrations', 'Integrations')
|
msg = msg.replace("integrations", "Integrations")
|
||||||
msg = msg.replace('patches', 'Patches')
|
msg = msg.replace("patches", "Patches")
|
||||||
|
|
||||||
for app in build_config:
|
for app in build_config:
|
||||||
if not build_config[app].getboolean('build'):
|
if not build_config[app].getboolean("build"):
|
||||||
continue
|
continue
|
||||||
msg = msg.replace(
|
msg = msg.replace(build_config[app]["apk"], build_config[app]["pretty_name"])
|
||||||
build_config[app]['apk'], build_config[app]['pretty_name'])
|
|
||||||
|
|
||||||
msg += '\nTimestamp: ' + timestamp
|
msg += "\nTimestamp: " + timestamp
|
||||||
if appstate['gmscore_updated']:
|
if appstate["gmscore_updated"]:
|
||||||
msg += '\nGmsCore was updated.'
|
msg += "\nGmsCore was updated."
|
||||||
|
|
||||||
config = appstate['notification_config']
|
config = appstate["notification_config"]
|
||||||
for entry in config:
|
for entry in config:
|
||||||
if not config[entry].getboolean('enabled'):
|
if not config[entry].getboolean("enabled"):
|
||||||
continue
|
continue
|
||||||
encoded_title = '⚙⚙⚙ ReVanced Build ⚙⚙⚙'.encode('utf-8')
|
encoded_title = "⚙⚙⚙ ReVanced Build ⚙⚙⚙".encode("utf-8")
|
||||||
|
|
||||||
if entry == 'ntfy':
|
if entry == "ntfy":
|
||||||
print('Sending notification through ntfy.sh...')
|
print("Sending notification through ntfy.sh...")
|
||||||
try:
|
try:
|
||||||
url = config[entry]['url']
|
url = config[entry]["url"]
|
||||||
topic = config[entry]['topic']
|
topic = config[entry]["topic"]
|
||||||
except:
|
except KeyError:
|
||||||
print('URL or TOPIC not provided!')
|
print("URL or TOPIC not provided!")
|
||||||
continue
|
continue
|
||||||
headers = {'Icon': 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Revanced-logo-round.svg/240px-Revanced-logo-round.svg.png',
|
headers = {
|
||||||
'Title': encoded_title}
|
"Icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Revanced-logo-round.svg/240px-Revanced-logo-round.svg.png",
|
||||||
|
"Title": encoded_title,
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
token = config[entry]['token']
|
token = config[entry]["token"]
|
||||||
headers['Authorization'] = 'Bearer ' + token
|
headers["Authorization"] = "Bearer " + token
|
||||||
except:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
req.post(f"{url}/{topic}", msg, headers=headers)
|
req.post(f"{url}/{topic}", msg, headers=headers)
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
print('Failed!' + str(e))
|
print(f"Failed with exception: {ex}")
|
||||||
|
|
||||||
elif entry == 'gotify':
|
elif entry == "gotify":
|
||||||
print('Sending notification through Gotify...')
|
print("Sending notification through Gotify...")
|
||||||
try:
|
try:
|
||||||
url = config[entry]['url']
|
url = config[entry]["url"]
|
||||||
token = config[entry]['token']
|
token = config[entry]["token"]
|
||||||
except:
|
except KeyError:
|
||||||
print('URL or TOKEN not provided!')
|
print("URL or TOKEN not provided!")
|
||||||
continue
|
continue
|
||||||
data = {'Title': encoded_title, 'message': msg, 'priority': '5'}
|
data = {"Title": encoded_title, "message": msg, "priority": "5"}
|
||||||
try:
|
try:
|
||||||
req.post(f"{url}/message?token={token}", data)
|
req.post(f"{url}/message?token={token}", data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Failed!' + str(e))
|
print("Failed!" + str(e))
|
||||||
|
|
||||||
elif entry == 'telegram':
|
elif entry == "telegram":
|
||||||
print('Sending notification through Telegram...')
|
print("Sending notification through Telegram...")
|
||||||
try:
|
try:
|
||||||
chat = config[entry]['chat']
|
chat = config[entry]["chat"]
|
||||||
token = config[entry]['token']
|
token = config[entry]["token"]
|
||||||
except:
|
except KeyError:
|
||||||
print('CHAT or TOKEN not provided!')
|
print("CHAT or TOKEN not provided!")
|
||||||
continue
|
continue
|
||||||
cmd = f"./telegram.sh -t {token} -c {chat} -T {encoded_title} -M \"{msg}\""
|
cmd = f'./telegram.sh -t {token} -c {chat} -T {encoded_title} -M "{msg}"'
|
||||||
try:
|
try:
|
||||||
with subprocess.Popen(cmd, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout as output:
|
with subprocess.Popen(
|
||||||
|
cmd, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||||
|
).stdout as output:
|
||||||
for line in output:
|
for line in output:
|
||||||
line_utf = line.decode('utf-8').strip('\n')
|
line_utf = line.decode("utf-8").strip("\n")
|
||||||
if line_utf:
|
if line_utf:
|
||||||
print(line_utf)
|
print(line_utf)
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
err_exit(f"Failed!\n{e}", appstate)
|
print(f"Failed to send notification with exception: {ex}")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('Don\'t know how to send notifications to ' + entry)
|
print("Don't know how to send notifications to " + entry)
|
||||||
|
|
|
@ -3,93 +3,105 @@
|
||||||
# SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com>
|
# SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-3.0-only
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import configparser as cp
|
import configparser as cp
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import requests as req
|
import requests as req
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from ReVancedBuilder.APKPure_dl import get_apks
|
from ReVancedBuilder.APKPure_dl import get_apks
|
||||||
|
from ReVancedBuilder.Cleanup import err_exit, move_apps
|
||||||
from ReVancedBuilder.JAVABuilder import build_apps
|
from ReVancedBuilder.JAVABuilder import build_apps
|
||||||
from ReVancedBuilder.Notifications import send_notif
|
|
||||||
from ReVancedBuilder.Cleanup import move_apps, err_exit
|
|
||||||
|
|
||||||
# Update the ReVanced tools, if needed
|
# Update the ReVanced tools, if needed
|
||||||
def update_tools(appstate):
|
def update_tools(appstate):
|
||||||
for item in ['revanced-cli', 'revanced-patches']:
|
for item in ["revanced-cli", "revanced-patches"]:
|
||||||
print(f"Checking updates for {item}...")
|
print(f"Checking updates for {item}...")
|
||||||
tools = appstate['tools']
|
tools = appstate["tools"]
|
||||||
tool = next(filter(lambda x: x['repository'] == 'revanced/'+item and x['content_type'] not in ['application/pgp-keys', 'application/json'], tools))
|
tool = next(
|
||||||
latest_ver = Version(tool['version'])
|
filter(
|
||||||
|
lambda x: x["repository"] == "revanced/" + item
|
||||||
|
and x["content_type"] not in ["application/pgp-keys", "application/json"],
|
||||||
|
tools,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
latest_ver = Version(tool["version"])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
present_ver = Version(appstate['present_vers'][item])
|
present_ver = Version(appstate["present_vers"][item])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
present_ver = Version('0')
|
present_ver = Version("0")
|
||||||
|
|
||||||
output_file = item+os.path.splitext(tool['name'])[1]
|
output_file = item + os.path.splitext(tool["name"])[1]
|
||||||
if flag == 'force' or not os.path.isfile(output_file) or present_ver < latest_ver:
|
if flag == "force" or not os.path.isfile(output_file) or present_ver < latest_ver:
|
||||||
appstate['up-to-date'] = False
|
appstate["up-to-date"] = False
|
||||||
print(f"{item} has an update ({str(present_ver)} -> {str(latest_ver)})")
|
print(f"{item} has an update ({str(present_ver)} -> {str(latest_ver)})")
|
||||||
if flag != 'checkonly':
|
if flag != "checkonly":
|
||||||
print(f"Downloading {output_file}...")
|
print(f"Downloading {output_file}...")
|
||||||
res = req.get(tool['browser_download_url'], stream=True)
|
res = req.get(tool["browser_download_url"], stream=True)
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
with open(output_file, 'wb') as f:
|
with open(output_file, "wb") as f:
|
||||||
for chunk in res.iter_content(chunk_size=8192):
|
for chunk in res.iter_content(chunk_size=8192):
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
appstate['present_vers'].update({item: str(latest_ver)})
|
appstate["present_vers"].update({item: str(latest_ver)})
|
||||||
print("Done!")
|
print("Done!")
|
||||||
|
|
||||||
return appstate
|
return appstate
|
||||||
|
|
||||||
|
|
||||||
# Update GmsCore, if needed
|
# Update GmsCore, if needed
|
||||||
def update_gmscore(appstate):
|
def update_gmscore(appstate):
|
||||||
print('Checking updates for GmsCore...')
|
print("Checking updates for GmsCore...")
|
||||||
# Pull the latest information using the ReVanced API
|
# Pull the latest information using the ReVanced API
|
||||||
try:
|
try:
|
||||||
data = req.get('https://api.revanced.app/v2/gmscore/releases/latest').json()['release']
|
data = req.get("https://api.revanced.app/v2/gmscore/releases/latest").json()["release"]
|
||||||
except req.exceptions.RequestException as e:
|
except req.exceptions.RequestException as e:
|
||||||
err_exit(f"Error fetching GmsCore information, {e}", appstate)
|
err_exit(f"Error fetching GmsCore information, {e}", appstate)
|
||||||
|
|
||||||
latest_ver = Version(data['metadata']['tag_name'])
|
latest_ver = Version(data["metadata"]["tag_name"])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
present_ver = Version(appstate['present_vers']['GmsCore'])
|
present_ver = Version(appstate["present_vers"]["GmsCore"])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
present_ver = Version('0')
|
present_ver = Version("0")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
variant = appstate['build_config']['gmscore']['variant']
|
variant = appstate["build_config"]["gmscore"]["variant"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
variant = "regular"
|
variant = "regular"
|
||||||
|
|
||||||
if variant == "alt":
|
if variant == "alt":
|
||||||
gmscore_link = next(filter(lambda x: "-hw-" in x['name'], data['assets']))['browser_download_url']
|
gmscore_link = next(filter(lambda x: "-hw-" in x["name"], data["assets"]))[
|
||||||
|
"browser_download_url"
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
gmscore_link = next(filter(lambda x: "-hw-" not in x['name'], data['assets']))['browser_download_url']
|
gmscore_link = next(filter(lambda x: "-hw-" not in x["name"], data["assets"]))[
|
||||||
|
"browser_download_url"
|
||||||
|
]
|
||||||
|
|
||||||
if flag == 'force' or not os.path.isfile('GmsCore.apk') or present_ver < latest_ver:
|
if flag == "force" or not os.path.isfile("GmsCore.apk") or present_ver < latest_ver:
|
||||||
appstate['up-to-date'] = False
|
appstate["up-to-date"] = False
|
||||||
print(f"GmsCore has an update ({str(present_ver)} -> {str(latest_ver)})")
|
print(f"GmsCore has an update ({str(present_ver)} -> {str(latest_ver)})")
|
||||||
if flag != 'checkonly':
|
if flag != "checkonly":
|
||||||
print(f"Downloading GmsCore...")
|
print("Downloading GmsCore...")
|
||||||
res = req.get(gmscore_link, stream=True)
|
res = req.get(gmscore_link, stream=True)
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
with open('GmsCore.apk', 'wb') as f:
|
with open("GmsCore.apk", "wb") as f:
|
||||||
for chunk in res.iter_content(chunk_size=8192):
|
for chunk in res.iter_content(chunk_size=8192):
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
appstate['present_vers'].update({'GmsCore': str(latest_ver)})
|
appstate["present_vers"].update({"GmsCore": str(latest_ver)})
|
||||||
print("Done!")
|
print("Done!")
|
||||||
appstate['gmscore_updated'] = True
|
appstate["gmscore_updated"] = True
|
||||||
|
|
||||||
return appstate
|
return appstate
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# The main function starts here
|
# The main function starts here
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
|
@ -99,111 +111,114 @@ appstate = {}
|
||||||
|
|
||||||
# Get a timestamp
|
# Get a timestamp
|
||||||
time = datetime.now()
|
time = datetime.now()
|
||||||
appstate['timestamp'] = time.strftime('%Y-%m-%dT%H:%M:%SZ')
|
appstate["timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
# Read arguments
|
# Read arguments
|
||||||
try:
|
try:
|
||||||
os.chdir(sys.argv[1])
|
os.chdir(sys.argv[1])
|
||||||
except IndexError:
|
except IndexError:
|
||||||
sys.exit('Please provide a working directory as argument!')
|
sys.exit("Please provide a working directory as argument!")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
sys.exit('Invalid working directory provided!')
|
sys.exit("Invalid working directory provided!")
|
||||||
|
|
||||||
# Try to make sure only one instance is running in a given working directory
|
# Try to make sure only one instance is running in a given working directory
|
||||||
try:
|
try:
|
||||||
if os.path.exists('lockfile'):
|
if os.path.exists("lockfile"):
|
||||||
raise FileExistsError
|
raise FileExistsError
|
||||||
with open('tmplockfile', 'x') as f:
|
with open("tmplockfile", "x") as f:
|
||||||
f.flush()
|
f.flush()
|
||||||
os.fsync(f.fileno())
|
os.fsync(f.fileno())
|
||||||
os.replace('tmplockfile', 'lockfile')
|
os.replace("tmplockfile", "lockfile")
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
sys.exit('Another instance is already running in the same working directory!')
|
sys.exit("Another instance is already running in the same working directory!")
|
||||||
|
|
||||||
# Set up logging
|
# Set up logging
|
||||||
try:
|
try:
|
||||||
os.mkdir('logs')
|
os.mkdir("logs")
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.addHandler(logging.FileHandler(f"logs/{appstate['timestamp']}.log", 'w'))
|
logger.addHandler(logging.FileHandler(f"logs/{appstate['timestamp']}.log", "w"))
|
||||||
print = logger.info
|
print = logger.info
|
||||||
appstate['logger'] = logger
|
appstate["logger"] = logger
|
||||||
|
|
||||||
# Get the flag
|
# Get the flag
|
||||||
try:
|
try:
|
||||||
flag = sys.argv[2]
|
flag = sys.argv[2]
|
||||||
except:
|
except IndexError:
|
||||||
flag = None
|
flag = None
|
||||||
|
|
||||||
if flag not in ['buildonly', 'checkonly', 'force', 'experimental', None]:
|
if flag not in ["buildonly", "checkonly", "force", "experimental", None]:
|
||||||
err_exit(f"Unknown flag: {flag}", appstate)
|
err_exit(f"Unknown flag: {flag}", appstate)
|
||||||
|
|
||||||
appstate['flag'] = flag
|
appstate["flag"] = flag
|
||||||
appstate['gmscore_updated'] = False
|
appstate["gmscore_updated"] = False
|
||||||
|
|
||||||
print(f"Started building ReVanced apps at {time.strftime('%d %B, %Y %H:%M:%S')}")
|
print(f"Started building ReVanced apps at {time.strftime('%d %B, %Y %H:%M:%S')}")
|
||||||
print('----------------------------------------------------------------------')
|
print("----------------------------------------------------------------------")
|
||||||
|
|
||||||
# Read configs
|
# Read configs
|
||||||
try:
|
try:
|
||||||
appstate['build_config']=cp.ConfigParser()
|
appstate["build_config"] = cp.ConfigParser()
|
||||||
appstate['build_config'].read_file(open('build_config', 'r'))
|
appstate["build_config"].read_file(open("build_config", "r"))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
err_exit('No build config provided, exiting. Please look at the GitHub page for more information:\n https://github.com/SinTan1729/ReVancedBuilder', appstate)
|
err_exit(
|
||||||
|
"No build config provided, exiting. Please look at the GitHub page for more information:\n https://github.com/SinTan1729/ReVancedBuilder",
|
||||||
|
appstate,
|
||||||
|
)
|
||||||
|
|
||||||
appstate['notification_config'] = cp.ConfigParser()
|
appstate["notification_config"] = cp.ConfigParser()
|
||||||
appstate['notification_config'].read('notification_config')
|
appstate["notification_config"].read("notification_config")
|
||||||
|
|
||||||
# Pull the latest information using the ReVanced API
|
# Pull the latest information using the ReVanced API
|
||||||
try:
|
try:
|
||||||
tools = req.get('https://api.revanced.app/tools').json()['tools']
|
tools = req.get("https://api.revanced.app/tools").json()["tools"]
|
||||||
appstate['tools'] = tools
|
appstate["tools"] = tools
|
||||||
except req.exceptions.RequestException as e:
|
except req.exceptions.RequestException as e:
|
||||||
err_exit(f"Error fetching patch list, {e}", appstate)
|
err_exit(f"Error fetching patch list, {e}", appstate)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open('versions.json', 'r') as f:
|
with open("versions.json", "r") as f:
|
||||||
appstate['present_vers'] = json.load(f)
|
appstate["present_vers"] = json.load(f)
|
||||||
except:
|
except FileNotFoundError:
|
||||||
# We'll treat empty as 0 later
|
# We'll treat empty as 0 later
|
||||||
appstate['present_vers'] = json.loads('{}')
|
appstate["present_vers"] = json.loads("{}")
|
||||||
|
|
||||||
appstate['up-to-date'] = True
|
appstate["up-to-date"] = True
|
||||||
# send_notif(appstate, error=False) # <,,,,,,,,<,,,,,,,,,,,,,
|
# send_notif(appstate, error=False) # <,,,,,,,,<,,,,,,,,,,,,,
|
||||||
if flag != 'buildonly':
|
if flag != "buildonly":
|
||||||
appstate = update_tools(appstate)
|
appstate = update_tools(appstate)
|
||||||
appstate = update_gmscore(appstate)
|
appstate = update_gmscore(appstate)
|
||||||
if (not appstate['up-to-date'] and flag != 'checkonly') or flag == 'force':
|
if (not appstate["up-to-date"] and flag != "checkonly") or flag == "force":
|
||||||
appstate = get_apks(appstate)
|
appstate = get_apks(appstate)
|
||||||
|
|
||||||
if (flag != 'checkonly' and not appstate['up-to-date']) or flag in ['force', 'buildonly']:
|
if (flag != "checkonly" and not appstate["up-to-date"]) or flag in ["force", "buildonly"]:
|
||||||
build_apps(appstate)
|
build_apps(appstate)
|
||||||
move_apps(appstate)
|
move_apps(appstate)
|
||||||
|
|
||||||
# Update version numbers in the versions.json file
|
# Update version numbers in the versions.json file
|
||||||
if appstate['up-to-date'] and flag != 'buildonly':
|
if appstate["up-to-date"] and flag != "buildonly":
|
||||||
print('There\'s nothing to do.')
|
print("There's nothing to do.")
|
||||||
elif flag != 'checkonly':
|
elif flag != "checkonly":
|
||||||
send_notif(appstate)
|
err_exit("", appstate, 0)
|
||||||
try:
|
try:
|
||||||
os.rename('versions.json', 'versions-old.json')
|
os.rename("versions.json", "versions-old.json")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if flag != 'buildonly':
|
if flag != "buildonly":
|
||||||
with open('versions.json', 'w') as f:
|
with open("versions.json", "w") as f:
|
||||||
json.dump(appstate['present_vers'], f, indent=4)
|
json.dump(appstate["present_vers"], f, indent=4)
|
||||||
try:
|
try:
|
||||||
cmd = f"{appstate['build_config']['post_script']['file']} {appstate['timestamp']}"
|
cmd = f"{appstate['build_config']['post_script']['file']} {appstate['timestamp']}"
|
||||||
print(f"Running the post command '{cmd}'")
|
print(f"Running the post command '{cmd}'")
|
||||||
subprocess.run(cmd, shell=True)
|
subprocess.run(cmd, shell=True)
|
||||||
except:
|
except Exception as ex:
|
||||||
pass
|
print(f"Got exception while running the build: '{ex}'")
|
||||||
|
|
||||||
# Delete the lockfile
|
# Delete the lockfile
|
||||||
os.remove('lockfile')
|
os.remove("lockfile")
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
Loading…
Reference in a new issue