Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions plugins/ChangeDownloadPath/Plugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package grzesiek11.aliucordplugins.changedownloadpath;

import android.app.DownloadManager;
import android.content.Context;
import android.content.Context;
import android.net.Uri;
import com.aliucord.annotations.AliucordPlugin;
import com.aliucord.api.SettingsAPI;
import com.aliucord.Logger;
import com.aliucord.patcher.InsteadHook;
import com.discord.utilities.io.NetworkUtils;
import java.io.File;
import kotlin.jvm.functions.Function1;

@AliucordPlugin(requiresRestart = false)
public class Plugin extends com.aliucord.entities.Plugin {
static final String PATH_SETTING_KEY = "path";
static final String PATH_SETTING_DEFAULT = "/storage/emulated/0/Download";

@Override
public void start(Context context) throws Throwable {
var settings = new SettingsAPI("ChangeDownloadPath");
this.settingsTab = new SettingsTab(Settings.class, SettingsTab.Type.PAGE).withArgs(settings);

this.patcher.patch(
NetworkUtils.class.getDeclaredMethod("downloadFile", Context.class, Uri.class, String.class, String.class, Function1.class, Function1.class),
new InsteadHook(param -> {
var uri = (Uri) param.args[1];
var filename = (String) param.args[2];
var description = (String) param.args[3];
var successCallback = param.args[4];
var errorCallback = param.args[5];

var downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
var downloadPath = settings.getString(PATH_SETTING_KEY, PATH_SETTING_DEFAULT);
var downloadUri = Uri.fromFile(new File(downloadPath));
var downloadRequest = new DownloadManager.Request(uri)
.setTitle(filename)
.setDescription(description)
.setDestinationUri(Uri.withAppendedPath(downloadUri, filename));
downloadManager.enqueue(downloadRequest);

return null;
})
);
}

@Override
public void stop(Context context) {
this.patcher.unpatchAll();
}
}
43 changes: 43 additions & 0 deletions plugins/ChangeDownloadPath/Settings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package grzesiek11.aliucordplugins.changedownloadpath;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import com.aliucord.api.SettingsAPI;
import com.aliucord.fragments.SettingsPage;
import com.aliucord.views.TextInput;

public class Settings extends SettingsPage {
private SettingsAPI settings;

Settings(SettingsAPI settings) {
this.settings = settings;
}

@Override
public void onViewCreated(View view, Bundle bundle) {
super.onViewCreated(view, bundle);
var context = this.requireContext();

this.setActionBarTitle("ChangeDownloadPath");

var pathSetting = new TextInput(context);
pathSetting.setHint("Path");
var pathEditText = pathSetting.getEditText();
pathEditText.setText(this.settings.getString(Plugin.PATH_SETTING_KEY, Plugin.PATH_SETTING_DEFAULT));
pathEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {}

@Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {}

@Override
public void afterTextChanged(Editable editable) {
Settings.this.settings.setString(Plugin.PATH_SETTING_KEY, editable.toString());
}
});
this.addView(pathSetting);
}
}
29 changes: 29 additions & 0 deletions plugins/ForceNotifications/Plugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package grzesiek11.aliucordplugins.forcenotifications;

import android.content.Context;
import com.aliucord.annotations.AliucordPlugin;
import com.aliucord.patcher.Hook;
import com.discord.utilities.fcm.NotificationRenderer;
import com.discord.utilities.fcm.NotificationClient;
import com.discord.utilities.fcm.NotificationData;

@AliucordPlugin(requiresRestart = false)
public class Plugin extends com.aliucord.entities.Plugin {
@Override
public void start(Context context) throws Throwable {
this.patcher.patch(
NotificationRenderer.class.getDeclaredMethod("displayInApp", Context.class, NotificationData.class),
new Hook(param -> {
var this_ = (NotificationRenderer) param.thisObject;
var notificationData = (NotificationData) param.args[1];

this_.display(context, notificationData, NotificationClient.INSTANCE.getSettings$app_productionGoogleRelease());
})
);
}

@Override
public void stop(Context context) {
patcher.unpatchAll();
}
}
58 changes: 58 additions & 0 deletions plugins/TextEmoji/Plugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package grzesiek11.aliucordplugins.textemoji;

import android.content.Context;
import com.aliucord.annotations.AliucordPlugin;
import com.aliucord.patcher.Hook;
import com.aliucord.patcher.InsteadHook;
import com.discord.api.message.reaction.MessageReaction;
import com.discord.stores.StoreEmoji;
import com.discord.utilities.textprocessing.node.EmojiNode;
import com.discord.views.ReactionView;
import java.util.regex.Pattern;

@AliucordPlugin(requiresRestart = false)
public class Plugin extends com.aliucord.entities.Plugin {
// This regex is not possible to match
private static final Pattern UNMATCHABLE_PATTERN = Pattern.compile("$a");

@Override
public void start(Context context) throws Throwable {
// Text emoji in message contents
// Could also be done by patching com.discord.utilities.textprocessing.Rules$PATTERN_UNICODE_EMOJI$2.invoke
// together with com.discord.utilities.textprocessing.Rules.replaceEmojiSurrogates,
// but I figured this is simpler.
patcher.patch(
StoreEmoji.class.getDeclaredMethod("getUnicodeEmojisPattern"),
InsteadHook.returnConstant(Plugin.UNMATCHABLE_PATTERN)
);

// Text emoji in reactions
patcher.patch(
EmojiNode.Companion.class.getDeclaredMethod("from", int.class, EmojiNode.EmojiIdAndType.class),
new Hook(param -> {
var emojiIdAndType = param.args[1];
if (emojiIdAndType instanceof EmojiNode.EmojiIdAndType.Unicode) {
param.setResult(null);
}
})
);

// Fix opacity in text emoji reactions
// This is a Discord bug that makes text emoji in reactions weirdly
// transparent, it's also present without the plugin, but it's only
// noticeable with emoji that don't have image replacements.
patcher.patch(
ReactionView.class.getDeclaredMethod("a", MessageReaction.class, long.class, boolean.class),
new Hook(param -> {
var this_ = (ReactionView) param.thisObject;
var reactionEmojiText = this_.o.e;
reactionEmojiText.setTextColor(0xffffffff);
})
);
}

@Override
public void stop(Context context) {
patcher.unpatchAll();
}
}
149 changes: 149 additions & 0 deletions plugins/sed/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package grzesiek11.aliucordplugins.sed;

import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Command {
private String replace;
private Pattern findRegex;
private boolean gFlag;

private Command(String replace, Pattern findRegex, boolean gFlag) {
this.replace = replace;
this.findRegex = findRegex;
this.gFlag = gFlag;
}

public static Optional<Command> parse(String commandString, boolean advanced) {
var findStringBuilder = new StringBuilder();
var replaceStringBuilder = new StringBuilder();
boolean gFlag = false;
var state = ParserState.COMMAND;
boolean escape = false;
int charIndex = 0;
loop: while (true) {
Optional<Character> ch;
if (charIndex < commandString.length()) {
ch = Optional.of(commandString.charAt(charIndex));
} else {
ch = Optional.empty();
}

switch (state) {
case COMMAND: {
if (ch.isPresent() && ch.get() == 's') {
state = ParserState.FIND_SLASH;
++charIndex;
break;
} else {
return Optional.empty();
}
}

case FIND_SLASH: {
if (ch.isPresent() && ch.get() == '/') {
state = ParserState.FIND;
++charIndex;
break;
} else {
return Optional.empty();
}
}

case FIND: {
if (!ch.isPresent()) {
return Optional.empty();
}
if (!escape) {
if (ch.get() == '\\') {
escape = true;
if (!advanced) {
findStringBuilder.append(ch.get());
++charIndex;
break;
}
} else if (ch.get() == '/') {
state = ParserState.REPLACE;
++charIndex;
break;
}
} else {
escape = false;
}
findStringBuilder.append(ch.get());
++charIndex;
break;
}

case REPLACE: {
if (!ch.isPresent()) {
state = ParserState.END;
break;
}
if (!escape) {
if (ch.get() == '\\' && advanced) {
escape = true;
} else if (ch.get() == '/' && advanced) {
state = ParserState.FLAGS;
++charIndex;
break;
}
} else {
escape = false;
}
replaceStringBuilder.append(ch.get());
++charIndex;
break;
}

case FLAGS: {
if (ch.isPresent()) {
if (ch.get() == 'g') {
gFlag = true;
state = ParserState.END;
++charIndex;
break;
} else {
return Optional.empty();
}
} else {
state = ParserState.END;
}
}

case END: {
if (!ch.isPresent()) {
break loop;
} else {
return Optional.empty();
}
}
}
}

var findString = findStringBuilder.toString();
var replaceString = replaceStringBuilder.toString();

String findRegexString;
String replace;
if (advanced) {
findRegexString = findString;
replace = replaceString;
} else {
findRegexString = Pattern.quote(findString);
replace = Matcher.quoteReplacement(replaceString);
}
var findRegex = Pattern.compile(findRegexString);
return Optional.of(new Command(replace, findRegex, gFlag));
}

public String replace(String text) {
var findMatcher = this.findRegex.matcher(text);
if (this.gFlag) {
return findMatcher.replaceAll(this.replace);
} else {
return findMatcher.replaceFirst(this.replace);
}
}
}
10 changes: 10 additions & 0 deletions plugins/sed/ParserState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package grzesiek11.aliucordplugins.sed;

enum ParserState {
COMMAND,
FIND_SLASH,
FIND,
REPLACE,
FLAGS,
END;
}
Loading