Skip to content

Commit

Permalink
[general] Bunny-fication
Browse files Browse the repository at this point in the history
  • Loading branch information
pylixonly committed Apr 30, 2024
1 parent e2b762d commit 68d03ad
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .idea/.name

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

3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
buildConfig = true
}
}

dependencies {
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 Pyoncord, a mod for Discord's mobile apps." />
android:value="An Xposed module to inject Bunny, a mod for Discord's mobile apps." />
<meta-data
android:name="xposedminversion"
android:value="82" />
Expand Down
72 changes: 69 additions & 3 deletions app/src/main/kotlin/io/github/pyoncord/xposed/FontsModule.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// credits to janisslsm from his PR: https://github.com/vendetta-mod/VendettaXposed/pull/17
// the functions hooked are based on the RN codebase, just modified to add fonts
// hooks are modified function from RN codebase

package io.github.pyoncord.xposed

Expand All @@ -10,32 +10,97 @@ 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.*
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.engine.cio.*
import io.ktor.client.statement.*
import io.ktor.client.plugins.*
import io.ktor.http.*

@Serializable
data class FontDefinition(
val name: String,
val description: String,
val spec: Int,
val hash: String,
val main: Map<String, String>,
)

class FontsModule: PyonModule() {
private val EXTENSIONS = arrayOf("", "_bold", "_italic", "_bold_italic")
private val FILE_EXTENSIONS = arrayOf(".ttf", ".otf")
private val FONTS_ASSET_PATH = "fonts/"

private lateinit var fontsDir: File
private lateinit var fontsAbsPath: String

override fun buildJson(builder: JsonObjectBuilder) {
builder.apply {
put("supportFonts", true)
put("fontPatch", 1)
}
}

override fun onInit(packageParam: XC_LoadPackage.LoadPackageParam) = with (packageParam) {
fontsDir = File(appInfo.dataDir, "files/pyoncord/fonts").also { it.mkdirs() }
val fontDefFile = File(appInfo.dataDir, "files/pyoncord/fonts.json")
if (!fontDefFile.exists()) return@with

val fontDef = try {
Json { ignoreUnknownKeys = true }.decodeFromString<FontDefinition>(fontDefFile.readText())
} catch (_: Throwable) { return@with }

fontsDir = File(appInfo.dataDir, "files/pyoncord/downloads/fonts").apply { mkdirs() }
fontsAbsPath = fontsDir.absolutePath + "/"

fontsDir.listFiles()?.forEach { file ->
val fileName = file.name
if (!fileName.startsWith(".")) {
val fontName = fileName.split('.')[0]
if (fontDef.main.keys.none { it == fontName }) {
Log.i("Bunny", "Deleting font file: $fileName")
file.delete()
}
}
}

val scope = MainScope()
val downloadJob = scope.async(Dispatchers.IO) {
fontDef.main.forEach { (name, url) ->
try {
Log.i("Bunny", "Downloading $name from $url")
val file = File(fontsDir, "$name${FILE_EXTENSIONS.first { url.endsWith(it) }}")
val client = HttpClient(CIO) {
install(UserAgent) { agent = "BunnyXposed" }
}

val response: HttpResponse = client.get(url)

if (response.status == HttpStatusCode.OK) {
file.writeBytes(response.body())
}

return@async
} catch (e: Throwable) {
Log.e("Bunny", "Failed to download fonts ($name from $url)")
}
}
}

XposedHelpers.findAndHookMethod("com.facebook.react.views.text.ReactFontManager", classLoader, "createAssetTypeface",
String::class.java,
Int::class.java,
Expand All @@ -44,6 +109,7 @@ class FontsModule: PyonModule() {
val fontFamilyName: String = param.args[0].toString();
val style: Int = param.args[1] as Int;
val assetManager: AssetManager = param.args[2] as AssetManager;
runBlocking { downloadJob.join() }
return createAssetTypeface(fontFamilyName, style, assetManager)
}
});
Expand Down
9 changes: 5 additions & 4 deletions app/src/main/kotlin/io/github/pyoncord/xposed/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,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.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
Expand Down Expand Up @@ -34,12 +35,12 @@ class Main : IXposedHookLoadPackage {
ThemeModule(),
SysColorsModule(),
FontsModule(),
// BubbleModule()
)

fun buildLoaderJsonString(): String {
val obj = buildJsonObject {
put("loaderName", "PyoncordXposed")
put("loaderName", "BunnyXposed")
put("loaderVersion", BuildConfig.VERSION_NAME)

for (module in pyonModules) {
module.buildJson(this)
Expand Down Expand Up @@ -104,7 +105,7 @@ class Main : IXposedHookLoadPackage {
install(HttpTimeout) {
requestTimeoutMillis = if (bundle.exists()) 3000 else HttpTimeout.INFINITE_TIMEOUT_MS
}
install(UserAgent) { agent = "PyoncordXposed" }
install(UserAgent) { agent = "BunnyXposed" }
}

val url =
Expand All @@ -127,7 +128,7 @@ class Main : IXposedHookLoadPackage {

return@async
} catch (e: Exception) {
Log.e("Pyoncord", "Failed to download Pyoncord")
Log.e("Bunny", "Failed to download bundle")
}
}

Expand Down
3 changes: 1 addition & 2 deletions app/src/main/kotlin/io/github/pyoncord/xposed/ThemeModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@ class ThemeModule : PyonModule() {

if (!themeFile.isValidish()) return null

val themeText = themeFile.readText()

return try {
val themeText = themeFile.readText()
Json { ignoreUnknownKeys = true }.decodeFromString<Theme>(themeText)
} catch (e: Exception) { null }
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">PyoncordXposed</string>
<string name="app_name">BunnyXposed</string>
</resources>
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = "PyoncordXposed"
rootProject.name = "BunnyXposed"
include(":app")

0 comments on commit 68d03ad

Please sign in to comment.