Skip to content

Commit

Permalink
initial commint
Browse files Browse the repository at this point in the history
  • Loading branch information
Arsylk committed Mar 25, 2020
0 parents commit ebc9557
Show file tree
Hide file tree
Showing 33 changed files with 736 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
/keystore.properties
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
38 changes: 38 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apply plugin: 'com.android.application'

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 28
defaultConfig {
applicationId "com.arsylk.xdiscord"
minSdkVersion 22
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
signingConfigs {
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(rootProject.file('keystore.properties')))
release {
keyAlias keystoreProperties.getProperty('keyAlias')
keyPassword keystoreProperties.getProperty('keyPassword')
storeFile file(keystoreProperties.getProperty('storeFile'))
storePassword keystoreProperties.getProperty('storePassword')
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
}
22 changes: 22 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.arsylk.xdiscord">

<application
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
tools:ignore="GoogleAppIndexingWarning">

<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="Enables nitro emoticons in Discord" />
<meta-data
android:name="xposedminversion"
android:value="53" />

</application>
</manifest>
1 change: 1 addition & 0 deletions app/src/main/assets/xposed_init
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.arsylk.xdiscord.XposedInit
39 changes: 39 additions & 0 deletions app/src/main/java/com/arsylk/xdiscord/Hooks/MessageEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.arsylk.xdiscord.Hooks;

import android.util.Pair;
import com.arsylk.xdiscord.XposedInit;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

import java.util.HashMap;


public abstract class MessageEntry {
public static class AllConstructorsHook extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object thisObject = param.thisObject;
XposedHelpers.setBooleanField(thisObject, "animateEmojis", true);

Object messageObject = XposedHelpers.getObjectField(thisObject, "message");
String messageContent = (String) XposedHelpers.getObjectField(messageObject, "content");
if(XposedHelpers.getAdditionalInstanceField(messageContent, "xHandled") == null) {
HashMap allEmojis = (HashMap) XposedHelpers.getAdditionalStaticField(XposedInit.StoreEmojiCustom, "allEmojis");
if(allEmojis != null) {
for(Object value : allEmojis.values()) {
Pair pair = (Pair) value;
String regexString = (String) pair.first, replaceString = (String) pair.second;

if(!messageContent.contains(replaceString))
messageContent = messageContent.replaceAll(regexString, (replaceString+" "));
}
}

XposedHelpers.setAdditionalInstanceField(messageContent, "xHandled", true);
XposedHelpers.setObjectField(messageObject,"content", messageContent);
XposedHelpers.setObjectField(thisObject, "message", messageObject);
}
}
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/com/arsylk/xdiscord/Hooks/ModelEmojiCustom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.arsylk.xdiscord.Hooks;

import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;


public abstract class ModelEmojiCustom {
public static class IsAvailableHook extends XC_MethodReplacement {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Object thisObject = param.thisObject;
XposedHelpers.setObjectField(thisObject, "available", Boolean.TRUE);

return Boolean.TRUE;
}
}
public static class IsUsableHook extends XC_MethodReplacement {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Object thisObject = param.thisObject;
XposedHelpers.setObjectField(thisObject, "isUsable", Boolean.TRUE);

return Boolean.TRUE;
}
}
}
37 changes: 37 additions & 0 deletions app/src/main/java/com/arsylk/xdiscord/Hooks/ModelMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.arsylk.xdiscord.Hooks;

import android.util.Pair;
import com.arsylk.xdiscord.XposedInit;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

import java.util.HashMap;

public abstract class ModelMessage {
public static class GetContentHook extends XC_MethodReplacement {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Object thisObject = param.thisObject;

String content = (String) XposedHelpers.getObjectField(thisObject, "content");
if(XposedHelpers.getAdditionalInstanceField(content, "xHandled") == null) {
HashMap allEmojis = (HashMap) XposedHelpers.getAdditionalStaticField(XposedInit.StoreEmojiCustom, "allEmojis");
if(allEmojis != null) {
for(Object value : allEmojis.values()) {
Pair pair = (Pair) value;
String regexString = (String) pair.first, replaceString = (String) pair.second;

content = content.replaceAll(regexString, replaceString);
}
}

XposedBridge.log(content);
XposedHelpers.setAdditionalInstanceField(content, "xHandled", true);
XposedHelpers.setObjectField(thisObject,"content", content);
}

return content;
}
}
}
38 changes: 38 additions & 0 deletions app/src/main/java/com/arsylk/xdiscord/Hooks/StoreEmojiCustom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.arsylk.xdiscord.Hooks;

import android.util.Pair;
import com.arsylk.xdiscord.XposedInit;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;

import java.util.HashMap;
import java.util.Map;

public abstract class StoreEmojiCustom {
public static class UpdateAvailableGuildEmojisHook extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object thisObject = param.thisObject;

HashMap<String, Pair<String, String>> allEmojis = new HashMap<>();
HashMap allGuildEmojis = (HashMap) XposedHelpers.getObjectField(thisObject, "allGuildEmojis");
if(allGuildEmojis != null) {
for(Object allGuildEmojisValue : allGuildEmojis.values()) {
if(allGuildEmojisValue != null) {
for(Object emoji : ((Map) allGuildEmojisValue).values()) {
String emojiIdStr = (String) XposedHelpers.callMethod(emoji, "getIdStr");
String emojiRegex = (String) XposedHelpers.callMethod(emoji, "getColonRegex");
String emojiReplace = (String) XposedHelpers.callMethod(emoji, "getMessageContentReplacement");

allEmojis.put(emojiIdStr, new Pair<>(emojiRegex, emojiReplace));
}
}
}
}



XposedHelpers.setAdditionalStaticField(XposedInit.StoreEmojiCustom, "allEmojis", allEmojis);
}
}
}
81 changes: 81 additions & 0 deletions app/src/main/java/com/arsylk/xdiscord/XposedInit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.arsylk.xdiscord;

import com.arsylk.xdiscord.Hooks.MessageEntry;
import com.arsylk.xdiscord.Hooks.ModelEmojiCustom;
import com.arsylk.xdiscord.Hooks.ModelMessage;
import com.arsylk.xdiscord.Hooks.StoreEmojiCustom;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import java.lang.reflect.Method;
import java.util.Collection;


public class XposedInit implements IXposedHookZygoteInit, IXposedHookLoadPackage {
public static final String DISCORD_PACKAGE = "com.discord";

public static Class StoreEmojiCustom = null;
private Method updateAvailableGuildEmojis = null;
public static Class ModelEmojiCustom = null;
private Method isAvailable = null, isUsable = null;
public static Class MessageEntry = null, ModelMessage = null;
private Method getContent = null;


@Override
public void initZygote(StartupParam startupParam) throws Throwable {
}

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if(!lpparam.packageName.equals(DISCORD_PACKAGE))
return;
XposedBridge.log("Loaded app: " + lpparam.packageName);


if(!findClasses(lpparam)) {
XposedBridge.log("Failed to find necessary classes");
return;
}
XposedBridge.log("All necessary classes found");

if(!findMethods(lpparam)) {
XposedBridge.log("Failed to find necessary methods");
return;
}
XposedBridge.log("All necessary methods found");


// hook methods
XposedBridge.hookMethod(updateAvailableGuildEmojis, new StoreEmojiCustom.UpdateAvailableGuildEmojisHook());
XposedBridge.hookMethod(isAvailable, new ModelEmojiCustom.IsAvailableHook());
XposedBridge.hookMethod(isUsable, new ModelEmojiCustom.IsUsableHook());
// XposedBridge.hookMethod(getContent, new ModelMessage.GetContentHook());

// hook constructors
XposedBridge.hookAllConstructors(MessageEntry, new MessageEntry.AllConstructorsHook());
}

private boolean findClasses(XC_LoadPackage.LoadPackageParam lpparam) {
StoreEmojiCustom = XposedHelpers.findClassIfExists("com.discord.stores.StoreEmojiCustom", lpparam.classLoader);
ModelEmojiCustom = XposedHelpers.findClassIfExists("com.discord.models.domain.emoji.ModelEmojiCustom", lpparam.classLoader);
MessageEntry = XposedHelpers.findClassIfExists("com.discord.widgets.chat.list.entries.MessageEntry", lpparam.classLoader);
ModelMessage = XposedHelpers.findClassIfExists("com.discord.models.domain.ModelMessage", lpparam.classLoader);

return (StoreEmojiCustom != null && ModelEmojiCustom != null && MessageEntry != null && ModelMessage != null);
}

private boolean findMethods(XC_LoadPackage.LoadPackageParam lpparam) {
updateAvailableGuildEmojis = XposedHelpers.findMethodExactIfExists(StoreEmojiCustom,
"updateAvailableGuildEmojis",
long.class, "com.discord.models.domain.ModelGuildMember", Collection.class);
isAvailable = XposedHelpers.findMethodExactIfExists(ModelEmojiCustom, "isAvailable");
isUsable = XposedHelpers.findMethodExactIfExists(ModelEmojiCustom, "isUsable");
getContent = XposedHelpers.findMethodExactIfExists(ModelMessage, "getContent");

return (updateAvailableGuildEmojis != null && isAvailable != null && isUsable != null && getContent != null);
}
}
34 changes: 34 additions & 0 deletions app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>
Loading

0 comments on commit ebc9557

Please sign in to comment.