[general] Bunny-fication
This commit is contained in:
parent
e2b762d387
commit
68d03add10
8 changed files with 82 additions and 13 deletions
2
.idea/.name
generated
2
.idea/.name
generated
|
|
@ -1 +1 @@
|
|||
PyoncordXposed
|
||||
BunnyXposed
|
||||
|
|
@ -33,6 +33,9 @@ android {
|
|||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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)
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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.*
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 =
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">PyoncordXposed</string>
|
||||
<string name="app_name">BunnyXposed</string>
|
||||
</resources>
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
rootProject.name = "PyoncordXposed"
|
||||
rootProject.name = "BunnyXposed"
|
||||
include(":app")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue