Skip to content

Commit

Permalink
feat: Rebrand to Revenge (#2)
Browse files Browse the repository at this point in the history
Co-authored-by: Palm <[email protected]>
Co-authored-by: pylixonly <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2024
1 parent 72af6df commit a5257fa
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 81 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ jobs:

- name: "Setup directories"
run: |
mkdir -p /tmp/pyonbuild/apks
mkdir -p /tmp/pyonbuild/tools
mkdir -p /tmp/build/apks
mkdir -p /tmp/build/tools
- name: "Move debug APK"
run: mv ./app/build/outputs/apk/debug/app-debug.apk /tmp/pyonbuild/apks
run: mv ./app/build/outputs/apk/debug/app-debug.apk /tmp/build/apks

- name: "Download uber-apk-signer"
run: wget -nv "https://github.com/patrickfav/uber-apk-signer/releases/download/v1.2.1/uber-apk-signer-1.2.1.jar" -O /tmp/pyonbuild/tools/uber-apk-signer.jar
run: wget -nv "https://github.com/patrickfav/uber-apk-signer/releases/download/v1.2.1/uber-apk-signer-1.2.1.jar" -O /tmp/build/tools/uber-apk-signer.jar

- name: "Sign release APK"
run: java -jar /tmp/pyonbuild/tools/uber-apk-signer.jar --apks ./app/build/outputs/apk/release/app-release-unsigned.apk --out /tmp/pyonbuild/apks/
run: java -jar /tmp/build/tools/uber-apk-signer.jar --apks ./app/build/outputs/apk/release/app-release-unsigned.apk --out /tmp/build/apks/

- name: "Rename release APK"
run: mv /tmp/pyonbuild/apks/app-release-aligned-debugSigned.apk /tmp/pyonbuild/apks/app-release.apk
run: mv /tmp/build/apks/app-release-aligned-debugSigned.apk /tmp/build/apks/app-release.apk

- name: "Upload debug APK"
uses: actions/upload-artifact@v3
with:
name: app-debug
path: /tmp/pyonbuild/apks/app-debug.apk
path: /tmp/build/apks/app-debug.apk

- name: "Upload release APK"
uses: actions/upload-artifact@v3
with:
name: app-release
path: /tmp/pyonbuild/apks/app-release.apk
path: /tmp/build/apks/app-release.apk
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/migrations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ plugins {
}

android {
namespace = "io.github.pyoncord.xposed"
namespace = "io.github.revenge.xposed"
compileSdk = 33

defaultConfig {
applicationId = "io.github.pyoncord.xposed"
applicationId = "io.github.revenge.xposed"
minSdk = 24
targetSdk = 33
versionCode = 203
versionName = "0.2.3"
versionCode = 204
versionName = "0.2.4"
}

buildTypes {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="An Xposed module to inject Bunny, a mod for Discord's mobile apps." />
android:value="An Xposed module to inject Revenge, a mod for Discord's mobile apps." />
<meta-data
android:name="xposedminversion"
android:value="82" />
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/assets/xposed_init
Original file line number Diff line number Diff line change
@@ -1 +1 @@
io.github.pyoncord.xposed.Main
io.github.revenge.xposed.Main
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
// credits to janisslsm from his PR: https://github.com/vendetta-mod/VendettaXposed/pull/17
// hooks are modified function from RN codebase

package io.github.pyoncord.xposed
package io.github.revenge.xposed

import android.content.res.AssetManager
import android.os.Build
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.Typeface.CustomFallbackBuilder
import android.graphics.fonts.Font
import android.graphics.fonts.FontFamily
import android.util.Log
import android.webkit.URLUtil
import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.*
import java.io.IOException
import java.io.File
import java.net.HttpURLConnection
import java.net.URL
import kotlinx.coroutines.*

import io.ktor.client.*
Expand All @@ -41,7 +36,7 @@ data class FontDefinition(
val main: Map<String, String>,
)

class FontsModule: PyonModule() {
class FontsModule: Module() {
private val EXTENSIONS = arrayOf("", "_bold", "_italic", "_bold_italic")
private val FILE_EXTENSIONS = arrayOf(".ttf", ".otf")
private val FONTS_ASSET_PATH = "fonts/"
Expand All @@ -67,7 +62,7 @@ class FontsModule: PyonModule() {
val assetManager: AssetManager = param.args[2] as AssetManager
return createAssetTypeface(fontFamilyName, style, assetManager)
}
});
})

val fontDefFile = File(appInfo.dataDir, "files/pyoncord/fonts.json")
if (!fontDefFile.exists()) return@with
Expand All @@ -85,7 +80,7 @@ class FontsModule: PyonModule() {
if (!fileName.startsWith(".")) {
val fontName = fileName.split('.')[0]
if (fontDef.main.keys.none { it == fontName }) {
Log.i("Bunny", "Deleting font file: $fileName")
Log.i("Revenge", "Deleting font file: $fileName")
file.delete()
}
}
Expand All @@ -97,12 +92,12 @@ class FontsModule: PyonModule() {
async {
val url = fontDef.main.getValue(name)
try {
Log.i("Bunny", "Downloading $name from $url")
Log.i("Revenge", "Downloading $name from $url")
val file = File(fontsDir, "$name${FILE_EXTENSIONS.first { url.endsWith(it) }}")
if (file.exists()) return@async

val client = HttpClient(CIO) {
install(UserAgent) { agent = "BunnyXposed" }
install(UserAgent) { agent = "RevengeXposed" }
}

val response: HttpResponse = client.get(url)
Expand All @@ -113,7 +108,7 @@ class FontsModule: PyonModule() {

return@async
} catch (e: Throwable) {
Log.e("Bunny", "Failed to download fonts ($name from $url)", e)
Log.e("Revenge", "Failed to download fonts ($name from $url)", e)
}
}
}.awaitAll()
Expand Down Expand Up @@ -144,7 +139,7 @@ class FontsModule: PyonModule() {
// ignore
}

for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filter { it != null }) {
for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filterNotNull()) {
for (fileExtension in FILE_EXTENSIONS) {
val fileName = java.lang.StringBuilder()
.append(fontRootPath)
Expand Down Expand Up @@ -220,7 +215,7 @@ class FontsModule: PyonModule() {

// Lastly, after all those checks above, this is the original RN logic for
// getting the typeface.
for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filter { it != null }) {
for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filterNotNull()) {
for (fileExtension in FILE_EXTENSIONS) {
val fileName = java.lang.StringBuilder()
.append(fontRootPath)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package io.github.pyoncord.xposed
package io.github.revenge.xposed

import android.app.Activity
import android.app.AndroidAppHelper
import android.content.Context
import android.app.Activity
import android.content.res.AssetManager
import android.content.res.Resources
import android.util.Log
Expand All @@ -12,7 +10,7 @@ import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage
import io.github.pyoncord.xposed.BuildConfig
import io.github.revenge.xposed.BuildConfig
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
Expand All @@ -36,7 +34,7 @@ data class LoaderConfig(
)

class Main : IXposedHookLoadPackage {
private val pyonModules: Array<PyonModule> = arrayOf(
private val modules: Array<Module> = arrayOf(
ThemeModule(),
SysColorsModule(),
FontsModule(),
Expand All @@ -47,7 +45,7 @@ class Main : IXposedHookLoadPackage {
put("loaderName", "BunnyXposed")
put("loaderVersion", BuildConfig.VERSION_NAME)

for (module in pyonModules) {
for (module in modules) {
module.buildJson(this)
}
}
Expand All @@ -56,24 +54,34 @@ class Main : IXposedHookLoadPackage {
}

override fun handleLoadPackage(param: XC_LoadPackage.LoadPackageParam) = with (param) {
// val reactActivity = runCatching {
// lpparam.classLoader.loadClass("com.discord.react_activities.ReactActivity")
// }.getOrElse { return } // Package is not our the target app, return
val reactActivity = runCatching {
classLoader.loadClass("com.discord.react_activities.ReactActivity")
}.getOrElse { return@with } // Package is not our the target app, return

// XposedBridge.hookMethod(reactActivity.getDeclaredMethod("onCreate", Bundle::class.java), object : XC_MethodHook() {
// override fun beforeHookedMethod(param: MethodHookParam) {
// init(lpparam, param.thisObject as Activity)
// }
// })
// }
var activity: Activity? = null;
val onActivityCreateCallback = mutableSetOf<(activity: Activity) -> Unit>()

// fun init(param: XC_LoadPackage.LoadPackageParam, activity: Activity) = with (param) {
// val catalystInstanceImpl = classLoader.loadClass("com.facebook.react.bridge.CatalystInstanceImpl")
val catalystInstanceImpl = runCatching {
classLoader.loadClass("com.facebook.react.bridge.CatalystInstanceImpl")
}.getOrElse { return@with }
XposedBridge.hookMethod(reactActivity.getDeclaredMethod("onCreate", Bundle::class.java), object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) {
activity = param.thisObject as Activity;
onActivityCreateCallback.forEach { cb -> cb(activity!!) }
onActivityCreateCallback.clear()
}
})

init(param) { cb ->
if (activity != null) cb(activity!!)
else onActivityCreateCallback.add(cb)
}
}

private fun init(
param: XC_LoadPackage.LoadPackageParam,
onActivityCreate: ((activity: Activity) -> Unit) -> Unit
) = with (param) {
val catalystInstanceImpl = classLoader.loadClass("com.facebook.react.bridge.CatalystInstanceImpl")

for (module in pyonModules) module.onInit(param)
for (module in modules) module.onInit(param)

val loadScriptFromAssets = catalystInstanceImpl.getDeclaredMethod(
"loadScriptFromAssets",
Expand Down Expand Up @@ -124,14 +132,14 @@ class Main : IXposedHookLoadPackage {
install(HttpTimeout) {
requestTimeoutMillis = if (bundle.exists()) 3000 else 10000
}
install(UserAgent) { agent = "BunnyXposed" }
install(UserAgent) { agent = "RevengeXposed" }
}

val url =
if (config.customLoadUrl.enabled) config.customLoadUrl.url
else "https://github.com/revenge-mod/Revenge/releases/latest/download/revenge.js"
else "https://github.com/revenge-mod/revenge-bundle/releases/latest/download/revenge.min.js"

Log.e("Bunny", "Fetching JS bundle from $url")
Log.e("Revenge", "Fetching JS bundle from $url")

val response: HttpResponse = client.get(url) {
headers {
Expand All @@ -153,13 +161,19 @@ class Main : IXposedHookLoadPackage {
return@async
} catch (e: RedirectResponseException) {
if (e.response.status != HttpStatusCode.NotModified) throw e;
Log.e("Bunny", "Server reponded with status code 304 - no changes to file")
Log.e("Revenge", "Server responded with status code 304 - no changes to file")
} catch (e: Throwable) {
// activity.runOnUiThread {
// Toast.makeText(activity.applicationContext, "Failed to fetch JS bundle, Bunny may not load!", Toast.LENGTH_SHORT).show()
// }
onActivityCreate { activity ->
activity.runOnUiThread {
Toast.makeText(
activity.applicationContext,
"Failed to fetch JS bundle, Revenge may not load!",
Toast.LENGTH_SHORT
).show()
}
}

Log.e("Bunny", "Failed to download bundle", e)
Log.e("Revenge", "Failed to download bundle", e)
}
}

Expand Down Expand Up @@ -211,4 +225,4 @@ class Main : IXposedHookLoadPackage {
})
}
}
}
}
Loading

0 comments on commit a5257fa

Please sign in to comment.