7_WEYBivYLUu)O
zd|ReE_JPqa8g+{En$gE;0Ga~%e?$QM3jq3YqJ`FK2C`{{#PzG@g{1=(LN>3TOj?0F
z!v5wGP*KT*?zgld4F5u*+E-H%!Lhf%13rqN;dPahP_-f&%zG=)soJ&@gz8z$6T&bP
z?g$2=m*8**$_Nce3CV(W)Z#mYniF`j!1EZKYiccHckq6@e#`T{HQGcK^K7!8u<+jU}>8!$>lP8$d67X^mc3h3jzZH
z00A%!1_>&LNQU(IiWgK)P}7#GVC;%K*Ou;vwr^XqV-$5vU_8qg#YB4E
zPZ7}I`=c{mYtZ*~D9fu2zOZs(f2)`0tRxZ*(V5v1J{31iTEltTv=-XDRSXHmD5s6T
zf~My9icjM=$vXUv`i!Q}*XSSLw67;nkr*8+hAcwE6Zn?ea-l`9WcF8=_B
z+m^GNrL~YmLLBpv?Qvg{$8yCC3!09r$Vp@Qq5Qs{crunQkC=&o_0PpG=%kPr1vhOs
zG>-n>51+kmB#0oHJSO`+
z62K2>Y{BbF=o^gE1Wddo!df4**~4j1ROkGd}_s^ByqTa>p4x`^x?sfVsj!?Fbr
z(kpxas@>6&;Qy!&le=<$N@kPa33JO$H%$=j{VXP~1kn{t)6+lnPPK6X`G>1~jlEn{
zqS3XFs;(KHHYp@?0!l$ieIA*EKnByC>kVP0J3C;4!VM1Tt{2elTg>yI
zGk|SO>)>1dKSzh1qKtPTDkShlou6(af)(Z+s*kS+j=l!)W(i7?_9ceEHl34My+~0S
z_YFgac7i|EJ4KpYQ3v$-2LUzXT>gppZ+G&8L>bA;CF?+i3qmy~9<;?EH{dWp`8u0S
zUo!$Y_2;68pA(&wp>E=J!-rQiA%Rj-9I27g9)j%+3?`-2@%*mh@Q8#CS#(LWt5a|U
zM4qDK`n&zQhDeU#Hn@`8SeWA%W4~uVh24oV0pFbS>lZocwI3~=&S>;~AtCgf=9^y4
z30ZJA!xQxETXTlz7R<}k)d29lyE3vn^F;`dNfFb8N?{rA+1mQ^aR98tx~;|f?WOg$
z7mFY0u9jTOKG$4D2lawlCt>FA>8C#v*=LQn8Y>%TL7>Z|TH;!S%5BT-p<=+%|w=xm{rj)~B944Wa*s6@A|=
zmPs%%KY%F?J_l{cz{TvAwKf%mRs19stvP&g3&{np)=ny|xHka~qt#prP7v6-nRe6j
z+{N-3?bah>0+*m>ZPtJ`lkwSUQKpv~hc2K&BHj;jt?&Qq;0*cS9~wdP;flv~tN^$i
zryw>dW+m1#Sc%(aY7;b82>^Yv*eZeT2T@MCfw~0v%1wtuc(wtkoh%EVbeok(h|yNJ
zhQ%UERuOA=n2=YFY9>zd7`ULAAVeG;k9#j^9IC|dk_eqD
zIun#o`Q^DoO}oDV5w8pYncyqrU04Hb+3(;!@Y4E}MKktn;URL+R2T+j3PRs@im9MC
zs3?a{SU4;hLQ#Q5nEBQKVU*Toen{unWpULKNonF7{LS`fe8kZ!0s7Tjwji`XS_L6ja6`&-N
zS~GPw5WOdy#X?=F!tI;5qo18vc+}rqnk8P73_*3>33KHG8G$twcb>xq;velt)L_q3
z0{fC~R!qe@B3f?0rGR`)EGgowEYJEq|F{`)5W!gJ=2H3hVfNLMw8R6I+v`QXO5R)f
zxG0a^1>pqR`NJ?|UW7M_uZNb}b;F?jA|oXVd&+5T7JIZ-GcCG4s%RSNY`9`d3!Ggs
zm9kvTXRuPQ_1eN;w_^_wnIl7^N#MZ{c`(on_i0Mdg_yd!{9hX|0wfh|-Bw;%Y$^fE
z!k-(v^s73{B_w)$DtVMxV1~Z~I(P0m8oC_7uKS*!F+j82j0qxRH?(3p{qUXF_FmP{
zY{FxvTceaqxu{RN&ykAv!bx+yDj!$h4Q(SIpQoMX7DZlq$DI-fz62a``-YI>Gn;?J^}f3h7#xnw3g
z5bsX#JeAGr0LDE!zd17p<}M8GF18T9EyX_qA$sX&$8V^3J=VR(-bd4gWw90}Tki-U
zrA8yVV0_Y_-avl5iXcr%w5h#1(Si@G2L;BvS#uZd+(Lv}Q1D0G!Vhc?=?@MQhXYq@LcE@w3H6(1~Tc;AAPkX7eM+$8UWBw%v&Ehz*Ci5ge2!8EhAlk`1hOR0sB3l`{~;(o<3o8j)TNG>pjs8$D(1GF!c-biER^`UMasM
zjpa26BwddKtYVZ%XD-obYT=0szxqxU0UxRS0M;#kTrd^GEI|MAH9WneY73KDx+7k1
z;LR?La+gHBAsLQ4b^phvNmk&%OZ9r_&8;j%aVmI(ApfLsB@sh`f9_+Ff#RNX&eOtM
zIJIKFzqR#ukD|($V#W^CO&(9kMgGg
zd0&AlOuT(=<&-iy*j{VdK->w`?Fs$>@DoBKX2lcwqK)@CQX~3aoIwbtRk!SdJC9}u
zdnDa#FqiR2Bcr{d6unZ8w7C;}6+MV$#|hB+g&}ws6Yy3Ivd(u0g@&?^%!orP6dF1^ZQFtw(EtRwP1gpQi
zyGQm6pO;Gm;mq^=koq3QKYL(b=J*=%@EdZY%pcqkoVoiUPuCnrrh22xSP`8oMwuD8
zM8sDT-&97S@0(r!0G)vtCfoO)843Q2i@i()%$)AE)OYYuNyZ1%xw8pO>Lx}m)EvP;
z_{i1DJ&{XgXG6uXS!8TidB@=x1B#fQ0gQvYQo$h0Zv@3Sn3^Gd8e8^089y96Y7G-I
zCmdX%f73w!ScC*F=jnoMA>G$haeruy$Ei}@%$|2CYGsuM(E?8a91msfEUs*ap`pfC
z^BRP~^bxWgV#Rf^x>ZByHA?e?{S6R)0mVj~w5iS%VG3Nm?Q0`vdjOmv+F|sfcOL@s
zSW`6DSN|)h)|XbbLuyCkFI)<(vO`_T$jmti);(;Gl{LEd55#-&qkVJ4iJ6h?@+N@T
a1f&3xk#$oL=R5b2^h-}>ZZRj~ZCRoHtlvlg
literal 0
HcmV?d00001
diff --git a/options.json b/options.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/options.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/revanced-magisk/META-INF/com/google/android/update-binary b/revanced-magisk/META-INF/com/google/android/update-binary
new file mode 100755
index 0000000..28b48e5
--- /dev/null
+++ b/revanced-magisk/META-INF/com/google/android/update-binary
@@ -0,0 +1,33 @@
+#!/sbin/sh
+
+#################
+# Initialization
+#################
+
+umask 022
+
+# echo before loading util_functions
+ui_print() { echo "$1"; }
+
+require_new_magisk() {
+ ui_print "*******************************"
+ ui_print " Please install Magisk v20.4+! "
+ ui_print "*******************************"
+ exit 1
+}
+
+#########################
+# Load util_functions.sh
+#########################
+
+OUTFD=$2
+ZIPFILE=$3
+
+mount /data 2>/dev/null
+
+[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
+. /data/adb/magisk/util_functions.sh
+[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
+
+install_module
+exit 0
diff --git a/revanced-magisk/META-INF/com/google/android/updater-script b/revanced-magisk/META-INF/com/google/android/updater-script
new file mode 100755
index 0000000..11d5c96
--- /dev/null
+++ b/revanced-magisk/META-INF/com/google/android/updater-script
@@ -0,0 +1 @@
+#MAGISK
diff --git a/scripts/customize.sh b/scripts/customize.sh
new file mode 100755
index 0000000..48e1711
--- /dev/null
+++ b/scripts/customize.sh
@@ -0,0 +1,117 @@
+# shellcheck disable=SC2148,SC2086
+ui_print ""
+
+if [ $ARCH = "arm" ]; then
+ #arm
+ ARCH_LIB=armeabi-v7a
+ alias cmpr='$MODPATH/bin/arm/cmpr'
+elif [ $ARCH = "arm64" ]; then
+ #arm64
+ ARCH_LIB=arm64-v8a
+ alias cmpr='$MODPATH/bin/arm64/cmpr'
+else
+ abort "ERROR: unsupported arch: ${ARCH}"
+fi
+set_perm_recursive $MODPATH/bin 0 0 0755 0777
+
+nsenter -t1 -m -- grep __PKGNAME /proc/mounts | while read -r line; do
+ ui_print "* Un-mount"
+ mp=${line#* }
+ mp=${mp%% *}
+ nsenter -t1 -m -- umount -l "${mp%%\\*}"
+done
+am force-stop __PKGNAME
+
+INS=true
+if BASEPATH=$(pm path __PKGNAME); then
+ BASEPATH=${BASEPATH##*:}
+ BASEPATH=${BASEPATH%/*}
+ if [ ${BASEPATH:1:6} = system ]; then
+ ui_print "* __PKGNAME is a system app"
+ elif [ ! -d ${BASEPATH}/lib ]; then
+ ui_print "* Invalid installation found. Uninstalling..."
+ pm uninstall -k --user 0 __PKGNAME
+ elif [ ! -f $MODPATH/__PKGNAME.apk ]; then
+ ui_print "* Stock __PKGNAME APK was not found"
+ VERSION=$(dumpsys package __PKGNAME | grep -m1 versionName)
+ VERSION="${VERSION#*=}"
+ if [ "$VERSION" = __PKGVER ] || [ -z "$VERSION" ]; then
+ ui_print "* Skipping stock installation"
+ INS=false
+ else
+ abort "ERROR: Version mismatch
+ installed: $VERSION
+ module: __PKGVER
+ "
+ fi
+ elif cmpr $BASEPATH/base.apk $MODPATH/__PKGNAME.apk; then
+ ui_print "* __PKGNAME is up-to-date"
+ INS=false
+ fi
+fi
+if [ $INS = true ]; then
+ if [ ! -f $MODPATH/__PKGNAME.apk ]; then
+ abort "ERROR: Stock __PKGNAME apk was not found"
+ fi
+ ui_print "* Updating __PKGNAME to __PKGVER"
+ settings put global verifier_verify_adb_installs 0
+ SZ=$(stat -c "%s" $MODPATH/__PKGNAME.apk)
+ if ! SES=$(pm install-create --user 0 -i com.android.vending -r -d -S "$SZ" 2>&1); then
+ ui_print "ERROR: install-create failed"
+ abort "$SES"
+ fi
+ SES=${SES#*[}
+ SES=${SES%]*}
+ set_perm "$MODPATH/__PKGNAME.apk" 1000 1000 644 u:object_r:apk_data_file:s0
+ if ! op=$(pm install-write -S "$SZ" "$SES" "__PKGNAME.apk" "$MODPATH/__PKGNAME.apk" 2>&1); then
+ ui_print "ERROR: install-write failed"
+ abort "$op"
+ fi
+ if ! op=$(pm install-commit "$SES" 2>&1); then
+ ui_print "ERROR: install-commit failed"
+ abort "$op"
+ fi
+ settings put global verifier_verify_adb_installs 1
+ if BASEPATH=$(pm path __PKGNAME); then
+ BASEPATH=${BASEPATH##*:}
+ BASEPATH=${BASEPATH%/*}
+ else
+ abort "ERROR: install __PKGNAME manually and reflash the module"
+ fi
+fi
+BASEPATHLIB=${BASEPATH}/lib/${ARCH}
+if [ -z "$(ls -A1 ${BASEPATHLIB})" ]; then
+ ui_print "* Extracting native libs"
+ mkdir -p $BASEPATHLIB
+ if ! op=$(unzip -j $MODPATH/__EXTRCT lib/${ARCH_LIB}/* -d ${BASEPATHLIB} 2>&1); then
+ ui_print "ERROR: extracting native libs failed"
+ abort "$op"
+ fi
+ set_perm_recursive ${BASEPATH}/lib 1000 1000 755 755 u:object_r:apk_data_file:s0
+fi
+ui_print "* Setting Permissions"
+set_perm $MODPATH/base.apk 1000 1000 644 u:object_r:apk_data_file:s0
+
+ui_print "* Mounting __PKGNAME"
+mkdir -p $NVBASE/rvhc
+RVPATH=$NVBASE/rvhc/${MODPATH##*/}.apk
+mv -f $MODPATH/base.apk $RVPATH
+
+if ! op=$(nsenter -t1 -m -- mount -o bind $RVPATH $BASEPATH/base.apk 2>&1); then
+ ui_print "ERROR: Mount failed!"
+ ui_print "$op"
+fi
+am force-stop __PKGNAME
+ui_print "* Optimizing __PKGNAME"
+nohup cmd package compile --reset __PKGNAME >/dev/null 2>&1 &
+
+ui_print "* Cleanup"
+rm -rf $MODPATH/bin $MODPATH/__PKGNAME.apk
+
+for s in "uninstall.sh" "service.sh"; do
+ sed -i "2 i\NVBASE=${NVBASE}" $MODPATH/$s
+done
+
+ui_print "* Done"
+ui_print " by j-hc (github.com/j-hc)"
+ui_print " "
diff --git a/scripts/service.sh b/scripts/service.sh
new file mode 100755
index 0000000..01d0cc3
--- /dev/null
+++ b/scripts/service.sh
@@ -0,0 +1,47 @@
+#!/system/bin/sh
+# shellcheck disable=SC2086
+MODDIR=${0%/*}
+RVPATH=$NVBASE/rvhc/${MODDIR##*/}.apk
+
+until [ "$(getprop sys.boot_completed)" = 1 ]; do sleep 1; done
+until [ -d "/sdcard/Android" ]; do sleep 1; done
+while
+ BASEPATH=$(pm path __PKGNAME)
+ svcl=$?
+ [ $svcl = 20 ]
+do sleep 2; done
+sleep 5
+
+err() {
+ [ ! -f $MODDIR/err ] && cp $MODDIR/module.prop $MODDIR/err
+ sed -i "s/^des.*/description=⚠️ Module is inactive: '${1}'/g" $MODDIR/module.prop
+}
+
+if [ $svcl = 0 ]; then
+ BASEPATH=${BASEPATH##*:}
+ BASEPATH=${BASEPATH%/*}
+ if [ -d $BASEPATH/lib ]; then
+ VERSION=$(dumpsys package __PKGNAME | grep -m1 versionName)
+ VERSION="${VERSION#*=}"
+ if [ "$VERSION" = __PKGVER ] || [ -z "$VERSION" ]; then
+ grep __PKGNAME /proc/mounts | while read -r line; do
+ mp=${line#* }
+ mp=${mp%% *}
+ umount -l ${mp%%\\*}
+ done
+ if chcon u:object_r:apk_data_file:s0 $RVPATH; then
+ mount -o bind $RVPATH $BASEPATH/base.apk
+ am force-stop __PKGNAME
+ [ -f $MODDIR/err ] && mv -f $MODDIR/err $MODDIR/module.prop
+ else
+ err "mount failed"
+ fi
+ else
+ err "version mismatch (installed:${VERSION}, module:__PKGVER)"
+ fi
+ else
+ err "invalid installation"
+ fi
+else
+ err "app not installed"
+fi
diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh
new file mode 100755
index 0000000..ab2372e
--- /dev/null
+++ b/scripts/uninstall.sh
@@ -0,0 +1,11 @@
+#!/system/bin/sh
+{
+ MODDIR=${0%/*}
+ rm "$NVBASE/rvhc/${MODDIR##*/}".apk
+ rmdir "$NVBASE/rvhc"
+ # if __ISBNDL; then
+ # until [ "$(getprop sys.boot_completed)" = 1 ]; do sleep 1; done
+ # sleep 15
+ # pm uninstall __PKGNAME
+ # fi
+} &
diff --git a/utils.sh b/utils.sh
new file mode 100755
index 0000000..d29a84a
--- /dev/null
+++ b/utils.sh
@@ -0,0 +1,557 @@
+#!/usr/bin/env bash
+
+MODULE_TEMPLATE_DIR="revanced-magisk"
+TEMP_DIR="temp"
+BUILD_DIR="build"
+
+if [ "${GITHUB_TOKEN:-}" ]; then GH_HEADER="Authorization: token ${GITHUB_TOKEN}"; else GH_HEADER=; fi
+NEXT_VER_CODE=${NEXT_VER_CODE:-$(date +'%Y%m%d')}
+REBUILD=${REBUILD:-false}
+OS=$(uname -o)
+
+SERVICE_SH=$(cat scripts/service.sh)
+CUSTOMIZE_SH=$(cat scripts/customize.sh)
+UNINSTALL_SH=$(cat scripts/uninstall.sh)
+
+# -------------------- json/toml --------------------
+json_get() { grep -o "\"${1}\":[^\"]*\"[^\"]*\"" | sed -E 's/".*".*"(.*)"/\1/'; }
+toml_prep() { __TOML__=$(tr -d '\t\r' <<<"$1" | tr "'" '"' | grep -o '^[^#]*' | grep -v '^$' | sed -r 's/(\".*\")|\s*/\1/g; 1i []'); }
+toml_get_table_names() {
+ local tn
+ tn=$(grep -x '\[.*\]' <<<"$__TOML__" | tr -d '[]') || return 1
+ if [ "$(sort <<<"$tn" | uniq -u | wc -l)" != "$(wc -l <<<"$tn")" ]; then
+ abort "ERROR: Duplicate tables in TOML"
+ fi
+ echo "$tn"
+}
+toml_get_table() { sed -n "/\[${1}]/,/^\[.*]$/p" <<<"$__TOML__" | sed '${/^\[/d;}'; }
+toml_get() {
+ local table=$1 key=$2 val
+ val=$(grep -m 1 "^${key}=" <<<"$table") && sed -e "s/^\"//; s/\"$//" <<<"${val#*=}"
+}
+# ---------------------------------------------------
+
+pr() { echo -e "\033[0;32m[+] ${1}\033[0m"; }
+epr() {
+ echo >&2 -e "\033[0;31m[-] ${1}\033[0m"
+ if [ "${GITHUB_REPOSITORY:-}" ]; then echo -e "::error::utils.sh [-] ${1}\n"; fi
+}
+abort() {
+ epr "ABORT: ${1:-}"
+ exit 1
+}
+
+get_rv_prebuilts() {
+ local integrations_src=$1 patches_src=$2 integrations_ver=$3 patches_ver=$4 cli_src=$5 cli_ver=$6
+ local patches_dir=${patches_src%/*}
+ patches_dir=${TEMP_DIR}/${patches_dir,,}-rv
+ local integrations_dir=${integrations_src%/*}
+ integrations_dir=${TEMP_DIR}/${integrations_dir,,}-rv
+ local cli_dir=${cli_src%/*}
+ cli_dir=${TEMP_DIR}/${cli_dir,,}-rv
+ mkdir -p "$patches_dir" "$integrations_dir" "$cli_dir"
+
+ pr "Getting prebuilts (${patches_src%/*})" >&2
+ local rv_cli_url rv_integrations_url rv_patches rv_patches_dl rv_patches_url rv_patches_json
+
+ local rv_cli_rel="https://api.github.com/repos/${cli_src}/releases/"
+ if [ "$cli_ver" ]; then rv_cli_rel+="tags/${cli_ver}"; else rv_cli_rel+="latest"; fi
+ local rv_integrations_rel="https://api.github.com/repos/${integrations_src}/releases/"
+ if [ "$integrations_ver" ]; then rv_integrations_rel+="tags/${integrations_ver}"; else rv_integrations_rel+="latest"; fi
+ local rv_patches_rel="https://api.github.com/repos/${patches_src}/releases/"
+ if [ "$patches_ver" ]; then rv_patches_rel+="tags/${patches_ver}"; else rv_patches_rel+="latest"; fi
+ rv_cli_url=$(gh_req "$rv_cli_rel" - | json_get 'browser_download_url') || return 1
+ local rv_cli_jar="${cli_dir}/${rv_cli_url##*/}"
+ echo "CLI: $(cut -d/ -f4 <<<"$rv_cli_url")/$(cut -d/ -f9 <<<"$rv_cli_url") " >"$patches_dir/changelog.md"
+
+ rv_integrations_url=$(gh_req "$rv_integrations_rel" - | json_get 'browser_download_url') || return 1
+ local rv_integrations_apk="${integrations_dir}/${rv_integrations_url##*/}"
+ echo "Integrations: $(cut -d/ -f4 <<<"$rv_integrations_url")/$(cut -d/ -f9 <<<"$rv_integrations_url") " >>"$patches_dir/changelog.md"
+
+ rv_patches=$(gh_req "$rv_patches_rel" -) || return 1
+ # rv_patches_changelog=$(json_get 'body' <<<"$rv_patches" | sed 's/\(\\n\)\+/\\n/g')
+ rv_patches_dl=$(json_get 'browser_download_url' <<<"$rv_patches")
+ rv_patches_json="${patches_dir}/patches-$(json_get 'tag_name' <<<"$rv_patches").json"
+ rv_patches_url=$(grep 'jar' <<<"$rv_patches_dl")
+ local rv_patches_jar="${patches_dir}/${rv_patches_url##*/}"
+ [ -f "$rv_patches_jar" ] || REBUILD=true
+ local nm
+ nm=$(cut -d/ -f9 <<<"$rv_patches_url")
+ echo "Patches: $(cut -d/ -f4 <<<"$rv_patches_url")/$nm " >>"$patches_dir/changelog.md"
+ # shellcheck disable=SC2001
+ echo -e "[Changelog](https://github.com/${patches_src}/releases/tag/v$(sed 's/.*-\(.*\)\..*/\1/' <<<"$nm"))\n" >>"$patches_dir/changelog.md"
+ # echo -e "\n${rv_patches_changelog//# [/### [}\n---" >>"$patches_dir/changelog.md"
+
+ dl_if_dne "$rv_cli_jar" "$rv_cli_url" >&2 || return 1
+ dl_if_dne "$rv_integrations_apk" "$rv_integrations_url" >&2 || return 1
+ dl_if_dne "$rv_patches_jar" "$rv_patches_url" >&2 || return 1
+ dl_if_dne "$rv_patches_json" "$(grep 'json' <<<"$rv_patches_dl")" >&2 || return 1
+
+ echo "$rv_cli_jar" "$rv_integrations_apk" "$rv_patches_jar" "$rv_patches_json"
+}
+
+get_prebuilts() {
+ if [ "$OS" = Android ]; then
+ local arch
+ if [ "$(uname -m)" = aarch64 ]; then arch=arm64; else arch=arm; fi
+ dl_if_dne ${TEMP_DIR}/aapt2 https://github.com/rendiix/termux-aapt/raw/d7d4b4a344cc52b94bcdab3500be244151261d8e/prebuilt-binary/${arch}/aapt2
+ chmod +x "${TEMP_DIR}/aapt2"
+ fi
+ mkdir -p ${MODULE_TEMPLATE_DIR}/bin/arm64 ${MODULE_TEMPLATE_DIR}/bin/arm
+ dl_if_dne "${MODULE_TEMPLATE_DIR}/bin/arm64/cmpr" "https://github.com/j-hc/cmpr/releases/latest/download/cmpr-arm64-v8a"
+ dl_if_dne "${MODULE_TEMPLATE_DIR}/bin/arm/cmpr" "https://github.com/j-hc/cmpr/releases/latest/download/cmpr-armeabi-v7a"
+
+ HTMLQ="${TEMP_DIR}/htmlq"
+ if [ ! -f "$HTMLQ" ]; then
+ if [ "$OS" = Android ]; then
+ if [ "$arch" = arm64 ]; then arch=arm64-v8a; else arch=armeabi-v7a; fi
+ dl_if_dne ${TEMP_DIR}/htmlq https://github.com/j-hc/htmlq-ndk/releases/latest/download/htmlq-${arch}
+ chmod +x $HTMLQ
+ else
+ if [ "${DRYRUN:-}" ]; then
+ : >"$HTMLQ"
+ else
+ req "https://github.com/mgdm/htmlq/releases/latest/download/htmlq-x86_64-linux.tar.gz" "${TEMP_DIR}/htmlq.tar.gz"
+ tar -xf "${TEMP_DIR}/htmlq.tar.gz" -C "$TEMP_DIR"
+ rm "${TEMP_DIR}/htmlq.tar.gz"
+ fi
+ fi
+
+ fi
+}
+
+config_update() {
+ declare -A sources
+ : >$TEMP_DIR/skipped
+ local conf=""
+ # shellcheck disable=SC2154
+ conf+=$(sed '1d' <<<"$main_config_t")
+ conf+=$'\n'
+ local prcfg=false
+ for table_name in $(toml_get_table_names); do
+ if [ -z "$table_name" ]; then continue; fi
+ t=$(toml_get_table "$table_name")
+ enabled=$(toml_get "$t" enabled) || enabled=true
+ if [ "$enabled" = false ]; then continue; fi
+ PATCHES_SRC=$(toml_get "$t" patches-source) || PATCHES_SRC=$DEF_PATCHES_SRC
+ if [[ -v sources[$PATCHES_SRC] ]]; then
+ if [ "${sources[$PATCHES_SRC]}" = 1 ]; then echo "$t"; fi
+ else
+ sources[$PATCHES_SRC]=0
+ if ! last_patches_url=$(gh_req "https://api.github.com/repos/${PATCHES_SRC}/releases/latest" - 2>&1 | json_get 'browser_download_url' | grep 'jar'); then
+ abort oops
+ fi
+ last_patches=${last_patches_url##*/}
+ cur_patches=$(sed -n "s/.*Patches: ${PATCHES_SRC%%/*}\/\(.*\)/\1/p" build.md | xargs)
+ if [ "$cur_patches" ] && [ "$last_patches" ]; then
+ if [ "${cur_patches}" != "$last_patches" ]; then
+ sources[$PATCHES_SRC]=1
+ prcfg=true
+ conf+="$t"
+ conf+=$'\n'
+ else
+ echo "Patches: ${PATCHES_SRC%%/*}/${cur_patches} " >>$TEMP_DIR/skipped
+ fi
+ fi
+ fi
+ done
+ if [ "$prcfg" = true ]; then echo "$conf"; fi
+}
+
+_req() {
+ if [ "$2" = - ]; then
+ wget -nv -O "$2" --header="$3" "$1"
+ else
+ local dlp
+ dlp="$(dirname "$2")/tmp.$(basename "$2")"
+ if [ -f "$dlp" ]; then
+ while [ -f "$dlp" ]; do sleep 1; done
+ return
+ fi
+ wget -nv -O "$dlp" --header="$3" "$1" || return 1
+ mv -f "$dlp" "$2"
+ fi
+}
+req() { _req "$1" "$2" "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0"; }
+gh_req() { _req "$1" "$2" "$GH_HEADER"; }
+
+log() { echo -e "$1 " >>"build.md"; }
+get_largest_ver() {
+ local vers m
+ vers=$(tee)
+ m=$(head -1 <<<"$vers")
+ if ! semver_validate "$m"; then echo "$m"; else sort -rV <<<"$vers" | head -1; fi
+}
+semver_validate() {
+ local a="${1%-*}"
+ local ac="${a//[.0-9]/}"
+ [ ${#ac} = 0 ]
+}
+get_patch_last_supported_ver() {
+ local inc_sel exc_sel vs
+ inc_sel=$(list_args "$2" | sed 's/.*/\.name == &/' | paste -sd '~' | sed 's/~/ or /g' || :)
+ exc_sel=$(list_args "$3" | sed 's/.*/\.name != &/' | paste -sd '~' | sed 's/~/ and /g' || :)
+ inc_sel=${inc_sel:-false}
+ if [ "$4" = false ]; then inc_sel="${inc_sel} or .use==true"; fi
+ if ! vs=$(jq -r ".[]
+ | select(.compatiblePackages // [] | .[] | .name==\"${1}\")
+ | select(${inc_sel})
+ | select(${exc_sel:-true})
+ | .compatiblePackages[].versions // []" "$5"); then
+ abort "error in jq query"
+ fi
+ tr -d ' ,\t[]"' <<<"$vs" | sort -u | grep -v '^$' | get_largest_ver || :
+}
+
+dl_if_dne() {
+ [ "${DRYRUN:-}" ] && {
+ : >"$1"
+ return 0
+ }
+ if [ ! -f "$1" ]; then
+ pr "Getting '$1' from '$2'"
+ req "$2" "$1"
+ fi
+}
+
+isoneof() {
+ local i=$1 v
+ shift
+ for v; do [ "$v" = "$i" ] && return 0; done
+ return 1
+}
+
+# -------------------- apkmirror --------------------
+dl_apkmirror() {
+ local url=$1 version=${2// /-} output=$3 arch=$4 dpi=$5 apkorbundle=APK
+ if [ "$arch" = "arm-v7a" ]; then arch="armeabi-v7a"; fi
+ [ "${DRYRUN:-}" ] && {
+ : >"$output"
+ return 0
+ }
+ local apparch resp node app_table dlurl=""
+ if [ "$arch" = all ]; then
+ apparch=(universal noarch 'arm64-v8a + armeabi-v7a')
+ else apparch=("$arch" universal noarch 'arm64-v8a + armeabi-v7a'); fi
+ url="${url}/${url##*/}-${version//./-}-release/"
+ resp=$(req "$url" -) || return 1
+ for ((n = 1; n < 40; n++)); do
+ node=$($HTMLQ "div.table-row.headerFont:nth-last-child($n)" -r "span:nth-child(n+3)" <<<"$resp")
+ if [ -z "$node" ]; then break; fi
+ app_table=$($HTMLQ --text --ignore-whitespace <<<"$node")
+ if [ "$(sed -n 3p <<<"$app_table")" = "$apkorbundle" ] && { [ "$apkorbundle" = BUNDLE ] ||
+ { [ "$apkorbundle" = APK ] && [ "$(sed -n 6p <<<"$app_table")" = "$dpi" ] &&
+ isoneof "$(sed -n 4p <<<"$app_table")" "${apparch[@]}"; }; }; then
+ dlurl=$($HTMLQ --base https://www.apkmirror.com --attribute href "div:nth-child(1) > a:nth-child(1)" <<<"$node")
+ break
+ fi
+ done
+ [ -z "$dlurl" ] && return 1
+ url=$(req "$dlurl" - | $HTMLQ --base https://www.apkmirror.com --attribute href "a.btn") || return 1
+ if [ "$apkorbundle" = BUNDLE ] && [[ "$url" != *"&forcebaseapk=true" ]]; then url="${url}&forcebaseapk=true"; fi
+ url=$(req "$url" - | $HTMLQ --base https://www.apkmirror.com --attribute href "span > a[rel = nofollow]") || return 1
+ req "$url" "$output"
+}
+get_apkmirror_vers() {
+ local vers apkm_resp
+ apkm_resp=$(req "https://www.apkmirror.com/uploads/?appcategory=${__APKMIRROR_CAT__}" -)
+ vers=$(sed -n 's;.*Version:\(.*\) .*;\1;p' <<<"$apkm_resp")
+ if [ "$__AAV__" = false ]; then
+ local IFS=$'\n'
+ vers=$(grep -iv "\(beta\|alpha\)" <<<"$vers")
+ local v r_vers=()
+ for v in $vers; do
+ grep -iq "${v} \(beta\|alpha\)" <<<"$apkm_resp" || r_vers+=("$v")
+ done
+ echo "${r_vers[*]}"
+ else
+ echo "$vers"
+ fi
+}
+get_apkmirror_pkg_name() { sed -n 's;.*id=\(.*\)" class="accent_color.*;\1;p' <<<"$__APKMIRROR_RESP__"; }
+get_apkmirror_resp() {
+ __APKMIRROR_RESP__=$(req "${1}" -)
+ __APKMIRROR_CAT__="${1##*/}"
+}
+# --------------------------------------------------
+
+# -------------------- uptodown --------------------
+get_uptodown_resp() {
+ __UPTODOWN_RESP__=$(req "${1}/versions" -)
+ __UPTODOWN_RESP_PKG__=$(req "${1}/download" -)
+}
+get_uptodown_vers() { $HTMLQ --text ".version" <<<"$__UPTODOWN_RESP__"; }
+dl_uptodown() {
+ local uptodown_dlurl=$1 version=$2 output=$3
+ local url
+ if [ -n "$version" ]; then
+ url=$(grep -F "${version}" -B 2 <<<"$__UPTODOWN_RESP__" | head -1 | sed -n 's;.*data-url=".*download\/\(.*\)".*;\1;p') || return 1
+ else url=""; fi
+ url="https://dw.uptodown.com/dwn/$(req "${uptodown_dlurl}/post-download/${url}" - | sed -n 's;.*class="post-download" data-url="\(.*\)".*;\1;p')" || return 1
+ req "$url" "$output"
+}
+get_uptodown_pkg_name() { $HTMLQ --text "tr.full:nth-child(1) > td:nth-child(3)" <<<"$__UPTODOWN_RESP_PKG__"; }
+# --------------------------------------------------
+
+# -------------------- apkmonk ---------------------
+get_apkmonk_resp() {
+ __APKMONK_RESP__=$(req "${1}" -)
+ __APKMONK_PKG_NAME__=$(awk -F/ '{print $NF}' <<<"$1")
+}
+get_apkmonk_vers() { grep -oP 'download_ver.+?>\K([0-9,\.]*)' <<<"$__APKMONK_RESP__"; }
+dl_apkmonk() {
+ local url=$1 version=$2 output=$3
+ url="https://www.apkmonk.com/down_file?pkg="$(grep -F "$version" <<<"$__APKMONK_RESP__" | grep -oP 'href=\"/download-app/\K.+?(?=/?\">)' | sed 's;/;\&key=;') || return 1
+ url=$(req "$url" - | grep -oP 'https.+?(?=\",)') || return 1
+ req "$url" "$output"
+}
+get_apkmonk_pkg_name() { echo "$__APKMONK_PKG_NAME__"; }
+# --------------------------------------------------
+dl_archive() {
+ local url=$1 version=$2 output=$3 arch=$4
+ local path version=${version// /}
+ path=$(grep "${version_f#v}-${arch// /}" <<<"$__ARCHIVE_RESP__") || return 1
+ req "${url}/${path}" "$output"
+}
+get_archive_resp() {
+ local r
+ r=$(req "$1" -)
+ if [ -z "$r" ]; then return 1; else __ARCHIVE_RESP__=$(sed -n 's;^ 10000000)); then
+ # pr "'${table}' bundle was downloaded successfully and will be used for the module"
+ # is_bundle=true
+ # else
+ # pr "'${table}' bundle was downloaded but will not be used"
+ # fi
+ # else
+ # pr "'${table}' bundle was not found"
+ # fi
+ # fi
+ # fi
+
+ if [ "${args[riplib]}" = true ]; then
+ p_patcher_args+=("--rip-lib x86_64 --rip-lib x86")
+ if [ "$arch" = "arm64-v8a" ]; then
+ p_patcher_args+=("--rip-lib armeabi-v7a")
+ elif [ "$arch" = "arm-v7a" ]; then
+ p_patcher_args+=("--rip-lib arm64-v8a")
+ fi
+ fi
+ if [ "$mode_arg" = module ]; then
+ build_mode_arr=(module)
+ elif [ "$mode_arg" = apk ]; then
+ build_mode_arr=(apk)
+ elif [ "$mode_arg" = both ]; then
+ build_mode_arr=(apk module)
+ fi
+ local patcher_args patched_apk build_mode
+ local rv_brand_f=${args[rv_brand],,}
+ rv_brand_f=${rv_brand_f// /-}
+ for build_mode in "${build_mode_arr[@]}"; do
+ patcher_args=("${p_patcher_args[@]}")
+ pr "Building '${table}' in '$build_mode' mode"
+ if [ -n "$microg_patch" ]; then
+ patched_apk="${TEMP_DIR}/${app_name_l}-${rv_brand_f}-${version_f}-${arch_f}-${build_mode}.apk"
+ if [ "$build_mode" = apk ]; then
+ patcher_args+=("-i \"${microg_patch}\"")
+ elif [ "$build_mode" = module ]; then
+ patcher_args+=("-e \"${microg_patch}\"")
+ fi
+ else
+ patched_apk="${TEMP_DIR}/${app_name_l}-${rv_brand_f}-${version_f}-${arch_f}.apk"
+ fi
+ if [ "$build_mode" = module ] && [ "${args[riplib]}" = true ]; then
+ patcher_args+=("--unsigned --rip-lib arm64-v8a --rip-lib armeabi-v7a")
+ fi
+ if [ ! -f "$patched_apk" ] || [ "$REBUILD" = true ]; then
+ if ! patch_apk "$stock_apk" "$patched_apk" "${patcher_args[*]}" "${args[cli]}" "${args[ptjar]}"; then
+ epr "Building '${table}' failed!"
+ return 0
+ fi
+ fi
+ if [ "$build_mode" = apk ]; then
+ local apk_output="${BUILD_DIR}/${app_name_l}-${rv_brand_f}-v${version_f}-${arch_f}.apk"
+ cp -f "$patched_apk" "$apk_output"
+ pr "Built ${table} (non-root): '${apk_output}'"
+ continue
+ fi
+ local base_template
+ base_template=$(mktemp -d -p $TEMP_DIR)
+ cp -a $MODULE_TEMPLATE_DIR/. "$base_template"
+ local upj="${table,,}-update.json"
+
+ local isbndl extrct stock_apk_module
+ if [ $is_bundle = true ]; then
+ isbndl=":"
+ extrct="base.apk"
+ stock_apk_module=$stock_bundle_apk
+ else
+ isbndl="! :"
+ extrct="${pkg_name}.apk"
+ stock_apk_module=$stock_apk
+ fi
+
+ uninstall_sh "$pkg_name" "$isbndl" "$base_template"
+ service_sh "$pkg_name" "$version" "$base_template"
+ customize_sh "$pkg_name" "$version" "$arch" "$extrct" "$base_template"
+ module_prop \
+ "${args[module_prop_name]}" \
+ "${app_name} ${args[rv_brand]}" \
+ "$version" \
+ "${app_name} ${args[rv_brand]} Magisk module" \
+ "https://raw.githubusercontent.com/${GITHUB_REPOSITORY:-}/update/${upj}" \
+ "$base_template"
+
+ local module_output="${app_name_l}-${rv_brand_f}-magisk-v${version_f}-${arch_f}.zip"
+ if [ ! -f "$module_output" ] || [ "$REBUILD" = true ]; then
+ pr "Packing module ${table}"
+ cp -f "$patched_apk" "${base_template}/base.apk"
+ if [ "${args[include_stock]}" = true ]; then cp -f "$stock_apk_module" "${base_template}/${pkg_name}.apk"; fi
+ pushd >/dev/null "$base_template" || abort "Module template dir not found"
+ zip -"$COMPRESSION_LEVEL" -FSqr "../../${BUILD_DIR}/${module_output}" .
+ popd >/dev/null || :
+ fi
+ pr "Built ${table} (root): '${BUILD_DIR}/${module_output}'"
+ done
+}
+
+list_args() { tr -d '\t\r' <<<"$1" | tr -s ' ' | sed 's/" "/"\n"/g' | sed 's/\([^"]\)"\([^"]\)/\1'\''\2/g' | grep -v '^$' || :; }
+join_args() { list_args "$1" | sed "s/^/${2} /" | paste -sd " " - || :; }
+
+uninstall_sh() {
+ local s="${UNINSTALL_SH//__PKGNAME/$1}"
+ echo "${s//__ISBNDL/$2}" >"${3}/uninstall.sh"
+}
+customize_sh() {
+ local s="${CUSTOMIZE_SH//__PKGNAME/$1}"
+ s="${s//__EXTRCT/$4}"
+ # shellcheck disable=SC2001
+ if [ "$3" = "arm64-v8a" ]; then
+ s=$(sed 's/#arm$/abort "ERROR: Wrong arch\nYour device: arm\nModule: arm64"/g' <<<"$s")
+ elif [ "$3" = "arm-v7a" ]; then
+ s=$(sed 's/#arm64$/abort "ERROR: Wrong arch\nYour device: arm64\nModule: arm"/g' <<<"$s")
+ fi
+ echo "${s//__PKGVER/$2}" >"${5}/customize.sh"
+}
+service_sh() {
+ local s="${SERVICE_SH//__PKGNAME/$1}"
+ echo "${s//__PKGVER/$2}" >"${3}/service.sh"
+}
+module_prop() {
+ echo "id=${1}
+name=${2}
+version=v${3}
+versionCode=${NEXT_VER_CODE}
+author=j-hc
+description=${4}" >"${6}/module.prop"
+
+ if [ "$ENABLE_MAGISK_UPDATE" = true ]; then echo "updateJson=${5}" >>"${6}/module.prop"; fi
+}