Compare commits

...

1 commit

Author SHA1 Message Date
7c02c9bac5 Implement slashcommands for discord api 2021-08-15 18:04:45 +01:00
18 changed files with 1163 additions and 0 deletions

View file

@ -3,6 +3,9 @@ FROM ubuntu:21.04
# Install needed packages # Install needed packages
RUN apt-get update RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install python3 android-sdk-build-tools wget unzip imagemagick git patch software-properties-common RUN DEBIAN_FRONTEND=noninteractive apt-get -y install python3 android-sdk-build-tools wget unzip imagemagick git patch software-properties-common
# Mirror is being weird currently so install this seperatly
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install zipmerge
# Install fdroid # Install fdroid
RUN add-apt-repository ppa:fdroid/fdroidserver RUN add-apt-repository ppa:fdroid/fdroidserver
@ -20,6 +23,9 @@ RUN wget -O ${CTC_FOLDER}/tools/apktool.jar https://f001.backblazeb2.com/file/av
# Grab xml-patch (https://github.com/dnault/xml-patch) # Grab xml-patch (https://github.com/dnault/xml-patch)
RUN wget -O ${CTC_FOLDER}/tools/xml-patch.jar https://jcenter.bintray.com/com/github/dnault/xml-patch/0.3.1/xml-patch-0.3.1.jar RUN wget -O ${CTC_FOLDER}/tools/xml-patch.jar https://jcenter.bintray.com/com/github/dnault/xml-patch/0.3.1/xml-patch-0.3.1.jar
# Grab dex2jar (https://github.com/Aliucord/dex2jar)
RUN wget -O ${CTC_FOLDER}/tools/dex2jar.jar https://github.com/Aliucord/dex2jar/releases/download/v19-fork2/dex2jar.jar
# Grab emoji sets # Grab emoji sets
ENV EMOJI_PATH=${CTC_FOLDER}/emojis ENV EMOJI_PATH=${CTC_FOLDER}/emojis
ENV EMOJI_MUTANT_PATH=${EMOJI_PATH}/mutant ENV EMOJI_MUTANT_PATH=${EMOJI_PATH}/mutant

View file

@ -0,0 +1,10 @@
#!/bin/bash
cd /opt/ctc/gitrepo/resources/patches/slashcommands/code
chmod +x gradlew
rm -rf build
./gradlew build
cd build/libs
/lib/android-sdk/build-tools/debian/dx --dex --output ctccommands.apk ctccommands-1.0-SNAPSHOT.jar
java -jar /opt/ctc/tools/apktool.jar d ctccommands.apk
cp -r ctccommands/smali/* ${DISTOK_EXTRACTED_DISCORD_PATH}/smali/

View file

@ -0,0 +1,13 @@
diff -crB com.discord-base/smali/com/discord/stores/BuiltInCommands.smali com.discord/smali/com/discord/stores/BuiltInCommands.smali
*** com.discord-base/smali/com/discord/stores/BuiltInCommands.smali 2021-08-15 15:01:18.951758400 +0100
--- com.discord/smali/com/discord/stores/BuiltInCommands.smali 2021-08-15 15:02:36.852775500 +0100
***************
*** 305,310 ****
--- 305,312 ----
iput-object v12, p0, Lcom/discord/stores/BuiltInCommands;->builtInApplication:Lcom/discord/models/commands/Application;
+ invoke-static {p0}, Lcom/cutthecord/commands/CTCCommands;->CreateCTCCommands(Lcom/discord/stores/BuiltInCommands;)V
+
return-void
.end method

View file

@ -0,0 +1,6 @@
.gradle
.idea
build
libs
out

View file

@ -0,0 +1,28 @@
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
implementation files('/tmp/cutthecord/discord-base-jar/discord-base.jar', 'libs/discord87202.jar')
}
test {
useJUnitPlatform()
}

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

View file

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,2 @@
rootProject.name = 'ctccommands'

View file

@ -0,0 +1,279 @@
package com.cutthecord.commands;
import com.cutthecord.commands.commands.*;
import com.discord.api.commands.ApplicationCommandType;
import com.discord.api.commands.CommandChoice;
import com.discord.models.commands.*;
import com.discord.stores.BuiltInCommands;
import d0.z.d.m;
import d0.z.d.o;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.DefaultConstructorMarker;
import java.lang.reflect.Field;
import java.util.*;
@SuppressWarnings("SameParameterValue")
public class CTCCommands {
static long ID = -100;
// Helper class for replacements
public static class StrPair {
final String a;
final String b;
public StrPair(String a, String b) {
this.a = a;
this.b = b;
}
}
// Need to inject a call at end of init for p0 to this class in BuiltinCommands.smali
// Create commands
@SuppressWarnings({"unused"})
public static void CreateCTCCommands(BuiltInCommands builtIn) {
// Used in command creation in BuiltinCommands, one more than the last reference
// TODO help text?
// Add existing commands
ArrayList<ApplicationCommand> commands = new ArrayList<>(builtIn.getBuiltInCommands());
// Add our commands
commands.add(createWrappedSlashCommand("st", "Puts a strikethrough the message", "Message", "~~", "~~")); // Strikethrough
commands.add(createWrappedSlashCommand("bold", "Makes text bold", "Message", "**", "**")); // Bold
commands.add(createWrappedSlashCommand("slap", "Slaps people with a large trout", "Message", "*Slaps ", " around a bit with a large trout.*")); // Slap
commands.add(createReplaceTextSlashCommand("clap", "Please \uD83D\uDC4F clap", "Message", Collections.singletonList(new StrPair(" ", ":clap:")))); // Clap
commands.add(createReplaceTextSlashCommand("flip", "Flips text (like “ʇɥıs”)", "Message", Replacements.FLIP)); // Flip
commands.add(createReplaceTextSlashCommand("fw", "Makes text fullwidth (like “Sent from my Android Device”)", "Message", Replacements.FULL_WIDTH)); // fw
commands.add(createReplaceTextSlashCommand("morse", "Converts text into morse code", "Message", Replacements.MORSE, Case.UPPER)); // morse
commands.add(createReplaceTextSlashCommand("gordon", "\uD835\uDDDB\uD835\uDDF2\uD835\uDDF9\uD835\uDDF9\uD835\uDDFC\uD835\uDDDA\uD835\uDDFC\uD835\uDDFF\uD835\uDDF1\uD835\uDDFC\uD835\uDDFB", "Message", Replacements.GORDON)); // gordon
commands.add(createReplaceTextSlashCommand("small", "Makes text smaller (like “ᴛʜɪs”)", "Message", Replacements.SMALL, Case.LOWER)); // small
commands.add(createReplaceTextSlashCommand("smaller", "Makes text even smaller (like “ᵗʰvˢ”)", "Message", Replacements.SMALLER, Case.LOWER)); // smaller
//noinspection unchecked
commands.add(createReplaceTextSlashCommand("upper", "Makes text uppercase", "Message", Collections.EMPTY_LIST, Case.UPPER)); // upper
//noinspection unchecked
commands.add(createReplaceTextSlashCommand("lower", "Makes text lowercase", "Message", Collections.EMPTY_LIST, Case.LOWER)); // lower
commands.add(createAppendToEndCommand("lenny", "( ͡° ͜ʖ ͡°)", "Message", " ( \u0361\u00B0 \u035C\u0296 \u0361\u00B0)")); // lenny
commands.add(createHandleRawMessageCommand("owo", "Myakes tyext reawwy owo-ly, nya :3", "Message", new CmdOwo())); // owo
commands.add(createHandleRawMessageCommand("emojify", "Emojify text", "Message", new CmdEmojify())); // emojify
// TODO
/*
cmds.put("spoilerimg", new CmdSpoilerImg());
// TODO can we add an CTC user that responds for these?
Command ctcCommand = new CmdCtc();
ctcCommand.registerSubCommand("channelleak", new CmdCtc.CmdCtcChannelLeak());
ctcCommand.registerSubCommand("showtyping", new CmdCtc.CmdCtcShowTyping());
ctcCommand.registerSubCommand("token", new CmdCtc.CmdCtcToken());
ctcCommand.registerSubCommand("account", new CmdCtc.CmdCtcAccount());
ctcCommand.registerSubCommand("addaccount", new CmdCtc.CmdCtcAddAccount());
ctcCommand.registerSubCommand("nodelete", new CmdCtc.CmdCtcNoDelete());
cmds.put("ctc", ctcCommand);
*/
// Builtin list is non modifiable, lets hijack it instead :)
try {
Field commandListField = BuiltInCommands.class.getDeclaredField("builtInCommands");
commandListField.setAccessible(true);
commandListField.set(builtIn, commands);
} catch (Exception e) {
System.out.println("Failed to replace buildInCommands");
e.printStackTrace();
}
}
// Wrapper for naming
public static class CTCCommand extends ApplicationCommand {
public CTCCommand(String id, long applicationID, String name, String description, Integer descriptionRes, List<ApplicationCommandOption> options, boolean builtIn, Long guildId, String version, Boolean defaultPermissions, Map map, Function1 handler, int flags, DefaultConstructorMarker defaultConstructorMarker) {
super(id, applicationID, name, description, descriptionRes, options, builtIn, guildId, version, defaultPermissions, map, handler, flags, defaultConstructorMarker);
}
}
// Wrapper for naming
public static ApplicationCommandOption makeOption(ApplicationCommandType type, String name, String description, Integer descriptionRes, boolean required, boolean defaultOpt, List<CommandChoice> choices, List<ApplicationCommandOption> options) {
return new ApplicationCommandOption(type, name, description, descriptionRes, required, defaultOpt, choices, options);
}
// Wrapper for naming
public static ApplicationCommandOption makeOption(ApplicationCommandType type, String name, String description, Integer descriptionRes, boolean required, boolean defaultOpt, List<CommandChoice> choices, List<ApplicationCommandOption> options, int flags, DefaultConstructorMarker marker) {
return new ApplicationCommandOption(type, name, description, descriptionRes, required, defaultOpt, choices, options, flags, marker);
/*
Flags
4 - description = null
8 - descriptionRes = null
64 - choices = null
128 - options = null
*/
}
// Wrapper for naming
public static ApplicationCommand makeCtcCommand(String name, String cmdDesc, List<ApplicationCommandOption> options, Function1<? super Map<String, ? extends Object>, String> handler) {
m.checkNotNullParameter(name, "name");
m.checkNotNullParameter(options, "options");
return new CTCCommand(String.valueOf(ID--), -1L, name, cmdDesc, null, options, true, null, null, null, null, handler, 1936, null);
/*
Flags
8 - description = null
16 - descriptionRes = null
64 - builtIn = false
128 - guildID = null
256 - version = null
512 - defaultPermissions = false
1024 - permissions = null
2048 - handler = null
1928 = 1024, 512, 256, 128, 8
// Lets try 1936 for out purposes
*/
}
static final class WrapTextCommand extends o<String> implements Function1<Map<String, ?>, String> {
public final String prefix;
public final String suffix;
public WrapTextCommand(String prefix, String suffix) {
super(1);
this.prefix = prefix;
this.suffix = suffix;
}
public final String invoke(Map<String, ?> options) {
m.checkNotNullParameter(options, "commandOptions");
StringBuilder newMessage = new StringBuilder();
newMessage.append(this.prefix);
Object originalMessage = options.get("message");
if (originalMessage == null) {
originalMessage = "";
}
newMessage.append(originalMessage);
newMessage.append(this.suffix);
return newMessage.toString();
}
}
@SuppressWarnings("SameParameterValue")
private static ApplicationCommand createWrappedSlashCommand(String name, String cmdDesc, String optionDesc, String prefix, String suffix) {
return makeCtcCommand(name, cmdDesc, Collections.singletonList(
makeOption(ApplicationCommandType.STRING, "message", optionDesc, null, true, false, null, null, 192, null)
), new WrapTextCommand(prefix, suffix));
}
final static class AppendToEndCommand extends o<String> implements Function1<Map<String, ?>, String> {
public String suffix;
public AppendToEndCommand(String suffix) {
super(1);
this.suffix = suffix;
}
public final String invoke(Map<String, ?> options) {
m.checkNotNullParameter( options, "commandOptions");
StringBuilder newMessage = new StringBuilder();
Object originalMessage = options.get("message");
if (originalMessage == null) {
originalMessage = "";
}
newMessage.append(originalMessage);
newMessage.append(' ');
newMessage.append(this.suffix);
return newMessage.toString();
}
}
@SuppressWarnings("SameParameterValue")
private static ApplicationCommand createAppendToEndCommand(String name, String cmdDesc, String optionDesc, String suffix) {
return makeCtcCommand(name, cmdDesc, Collections.singletonList(
makeOption(ApplicationCommandType.STRING, "message", optionDesc, null, false, false, null, null, 192, null)
), new AppendToEndCommand(suffix));
}
final static class ReplaceMatchesCommand extends o<String> implements Function1<Map<String, ?>, String> {
public final List<StrPair> replacements;
public final Case c;
public ReplaceMatchesCommand(List<StrPair> replacements, Case c) {
super(1);
this.replacements = replacements;
this.c = c;
}
public final String invoke(Map<String, ?> options) {
m.checkNotNullParameter(options, "commandOptions");
StringBuilder newMessage = new StringBuilder();
Object originalMessage = options.get("message");
if (originalMessage == null) {
originalMessage = "";
}
if (c == Case.UPPER) {
originalMessage = ((String)originalMessage).toUpperCase();
} else if (c == Case.LOWER) {
originalMessage = ((String)originalMessage).toLowerCase();
}
for (StrPair replacement : replacements) {
originalMessage = ((String)originalMessage).replace(replacement.a, replacement.b);
}
newMessage.append(originalMessage);
return newMessage.toString();
}
}
enum Case {
UPPER,
LOWER,
ORIGINAL
}
private static ApplicationCommand createReplaceTextSlashCommand(String name, String cmdDesc, String optionDesc, List<StrPair> replaceList, Case c) {
return makeCtcCommand(name, cmdDesc, Collections.singletonList(
makeOption(ApplicationCommandType.STRING, "message", optionDesc, null, true, true, null, null, 192, null)
), new ReplaceMatchesCommand(replaceList, c));
}
private static ApplicationCommand createReplaceTextSlashCommand(String name, String cmdDesc, String optionDesc, List<StrPair> replaceList) {
return createReplaceTextSlashCommand(name, cmdDesc, optionDesc, replaceList, Case.ORIGINAL);
}
final static class RawMessageCommand extends o<String> implements Function1<Map<String, ?>, String> {
public final RawMsgHandler handler;
public RawMessageCommand(RawMsgHandler handler) {
super(1);
this.handler = handler;
}
public final String invoke(Map<String, ?> options) {
m.checkNotNullParameter(options, "commandOptions");
StringBuilder newMessage = new StringBuilder();
Object originalMessage = options.get("message");
if (originalMessage == null) {
originalMessage = "";
}
newMessage.append(handler.processRawMessage((String) originalMessage));
return newMessage.toString();
}
}
private static ApplicationCommand createHandleRawMessageCommand(String name, String cmdDesc, String optionDesc, RawMsgHandler handler) {
return makeCtcCommand(name, cmdDesc, Collections.singletonList(
makeOption(ApplicationCommandType.STRING, "message", optionDesc, null, false, false, null, null, 192, null)
), new RawMessageCommand(handler));
}
}

View file

@ -0,0 +1,7 @@
package com.cutthecord.commands;
public interface RawMsgHandler {
String processRawMessage(String orig);
}

View file

@ -0,0 +1,304 @@
package com.cutthecord.commands;
import java.util.ArrayList;
import java.util.List;
public class Replacements {
public static final List<CTCCommands.StrPair> FLIP = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair("a", "ɐ"));
add(new CTCCommands.StrPair("b", "q"));
add(new CTCCommands.StrPair("c", "ɔ"));
add(new CTCCommands.StrPair("d", "p"));
add(new CTCCommands.StrPair("e", "ǝ"));
add(new CTCCommands.StrPair("f", "ɟ"));
add(new CTCCommands.StrPair("g", "ƃ"));
add(new CTCCommands.StrPair("h", "ɥ"));
add(new CTCCommands.StrPair("i", "ı"));
add(new CTCCommands.StrPair("j", "ɾ"));
add(new CTCCommands.StrPair("k", "ʞ"));
add(new CTCCommands.StrPair("l", "ן"));
add(new CTCCommands.StrPair("m", "ɯ"));
add(new CTCCommands.StrPair("n", "u"));
//add(new CTCCommands.StrPair("o", "o"));
add(new CTCCommands.StrPair("p", "d"));
add(new CTCCommands.StrPair("q", "b"));
add(new CTCCommands.StrPair("r", "ɹ"));
//add(new CTCCommands.StrPair("s", "s"));
add(new CTCCommands.StrPair("t", "ʇ"));
add(new CTCCommands.StrPair("u", "n"));
add(new CTCCommands.StrPair("v", "ʌ"));
add(new CTCCommands.StrPair("w", "ʍ"));
//add(new CTCCommands.StrPair("x", "x"));
add(new CTCCommands.StrPair("y", "ʎ"));
//add(new CTCCommands.StrPair("z", "z"));
}};
public static final List<CTCCommands.StrPair> FULL_WIDTH = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair(" ", " "));
add(new CTCCommands.StrPair("!", ""));
add(new CTCCommands.StrPair("#", ""));
add(new CTCCommands.StrPair("$", ""));
add(new CTCCommands.StrPair("%", ""));
add(new CTCCommands.StrPair("&", ""));
add(new CTCCommands.StrPair("'", ""));
add(new CTCCommands.StrPair("(", ""));
add(new CTCCommands.StrPair(")", ""));
add(new CTCCommands.StrPair("*", ""));
add(new CTCCommands.StrPair("+", ""));
add(new CTCCommands.StrPair(",", ""));
add(new CTCCommands.StrPair("-", ""));
add(new CTCCommands.StrPair(".", ""));
add(new CTCCommands.StrPair("/", ""));
add(new CTCCommands.StrPair("0", ""));
add(new CTCCommands.StrPair("1", ""));
add(new CTCCommands.StrPair("2", ""));
add(new CTCCommands.StrPair("3", ""));
add(new CTCCommands.StrPair("4", ""));
add(new CTCCommands.StrPair("5", ""));
add(new CTCCommands.StrPair("6", ""));
add(new CTCCommands.StrPair("7", ""));
add(new CTCCommands.StrPair("8", ""));
add(new CTCCommands.StrPair("9", ""));
add(new CTCCommands.StrPair(":", ""));
add(new CTCCommands.StrPair(";", ""));
add(new CTCCommands.StrPair("<", ""));
add(new CTCCommands.StrPair("=", ""));
add(new CTCCommands.StrPair(">", ""));
add(new CTCCommands.StrPair("?", ""));
add(new CTCCommands.StrPair("@", ""));
add(new CTCCommands.StrPair("A", ""));
add(new CTCCommands.StrPair("B", ""));
add(new CTCCommands.StrPair("C", ""));
add(new CTCCommands.StrPair("D", ""));
add(new CTCCommands.StrPair("E", ""));
add(new CTCCommands.StrPair("F", ""));
add(new CTCCommands.StrPair("G", ""));
add(new CTCCommands.StrPair("H", ""));
add(new CTCCommands.StrPair("I", ""));
add(new CTCCommands.StrPair("J", ""));
add(new CTCCommands.StrPair("K", ""));
add(new CTCCommands.StrPair("L", ""));
add(new CTCCommands.StrPair("M", ""));
add(new CTCCommands.StrPair("N", ""));
add(new CTCCommands.StrPair("O", ""));
add(new CTCCommands.StrPair("P", ""));
add(new CTCCommands.StrPair("Q", ""));
add(new CTCCommands.StrPair("R", ""));
add(new CTCCommands.StrPair("S", ""));
add(new CTCCommands.StrPair("T", ""));
add(new CTCCommands.StrPair("U", ""));
add(new CTCCommands.StrPair("V", ""));
add(new CTCCommands.StrPair("W", ""));
add(new CTCCommands.StrPair("X", ""));
add(new CTCCommands.StrPair("Y", ""));
add(new CTCCommands.StrPair("Z", ""));
add(new CTCCommands.StrPair("[", ""));
add(new CTCCommands.StrPair("]", ""));
add(new CTCCommands.StrPair("^", ""));
add(new CTCCommands.StrPair("_", "_"));
add(new CTCCommands.StrPair("`", ""));
add(new CTCCommands.StrPair("a", ""));
add(new CTCCommands.StrPair("b", ""));
add(new CTCCommands.StrPair("c", ""));
add(new CTCCommands.StrPair("d", ""));
add(new CTCCommands.StrPair("e", ""));
add(new CTCCommands.StrPair("f", ""));
add(new CTCCommands.StrPair("g", ""));
add(new CTCCommands.StrPair("h", ""));
add(new CTCCommands.StrPair("i", ""));
add(new CTCCommands.StrPair("j", ""));
add(new CTCCommands.StrPair("k", ""));
add(new CTCCommands.StrPair("l", ""));
add(new CTCCommands.StrPair("m", ""));
add(new CTCCommands.StrPair("n", ""));
add(new CTCCommands.StrPair("o", ""));
add(new CTCCommands.StrPair("p", ""));
add(new CTCCommands.StrPair("q", ""));
add(new CTCCommands.StrPair("r", ""));
add(new CTCCommands.StrPair("s", ""));
add(new CTCCommands.StrPair("t", ""));
add(new CTCCommands.StrPair("u", ""));
add(new CTCCommands.StrPair("v", ""));
add(new CTCCommands.StrPair("w", ""));
add(new CTCCommands.StrPair("x", ""));
add(new CTCCommands.StrPair("y", ""));
add(new CTCCommands.StrPair("z", ""));
add(new CTCCommands.StrPair("{", ""));
add(new CTCCommands.StrPair("|", ""));
add(new CTCCommands.StrPair("}", ""));
add(new CTCCommands.StrPair("~", ""));
}};
public static final List<CTCCommands.StrPair> MORSE = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair(" ", "/ "));
add(new CTCCommands.StrPair(".", ".-.-.- "));
add(new CTCCommands.StrPair(",", "--..-- "));
add(new CTCCommands.StrPair(":", "---... "));
add(new CTCCommands.StrPair("?", "..--.. "));
add(new CTCCommands.StrPair("'", ".----. "));
add(new CTCCommands.StrPair("-", "-....- "));
add(new CTCCommands.StrPair("/", "-..-. "));
add(new CTCCommands.StrPair("@", ".--.-. "));
add(new CTCCommands.StrPair("=", "-...- "));
add(new CTCCommands.StrPair("A", ".- "));
add(new CTCCommands.StrPair("B", "-... "));
add(new CTCCommands.StrPair("C", "-.-. "));
add(new CTCCommands.StrPair("D", "-.. "));
add(new CTCCommands.StrPair("E", ". "));
add(new CTCCommands.StrPair("F", "..-. "));
add(new CTCCommands.StrPair("G", "--. "));
add(new CTCCommands.StrPair("H", ".... "));
add(new CTCCommands.StrPair("I", ".. "));
add(new CTCCommands.StrPair("J", ".--- "));
add(new CTCCommands.StrPair("K", "-.- "));
add(new CTCCommands.StrPair("L", ".-.. "));
add(new CTCCommands.StrPair("M", "-- "));
add(new CTCCommands.StrPair("N", "-. "));
add(new CTCCommands.StrPair("O", "--- "));
add(new CTCCommands.StrPair("P", ".--. "));
add(new CTCCommands.StrPair("Q", "--.- "));
add(new CTCCommands.StrPair("R", ".-. "));
add(new CTCCommands.StrPair("S", "... "));
add(new CTCCommands.StrPair("T", "- "));
add(new CTCCommands.StrPair("U", "..- "));
add(new CTCCommands.StrPair("V", "...- "));
add(new CTCCommands.StrPair("W", ".-- "));
add(new CTCCommands.StrPair("X", "-..- "));
add(new CTCCommands.StrPair("Y", "-.-- "));
add(new CTCCommands.StrPair("Z", "--.. "));
add(new CTCCommands.StrPair("0", "----- "));
add(new CTCCommands.StrPair("1", ".---- "));
add(new CTCCommands.StrPair("2", "..--- "));
add(new CTCCommands.StrPair("3", "...-- "));
add(new CTCCommands.StrPair("4", "....- "));
add(new CTCCommands.StrPair("5", "..... "));
add(new CTCCommands.StrPair("6", "-.... "));
add(new CTCCommands.StrPair("7", "--... "));
add(new CTCCommands.StrPair("8", "---.. "));
add(new CTCCommands.StrPair("9", "----. "));
}};
public static final List<CTCCommands.StrPair> GORDON = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair("a", "𝗮"));
add(new CTCCommands.StrPair("b", "𝗯"));
add(new CTCCommands.StrPair("c", "𝗰"));
add(new CTCCommands.StrPair("d", "𝗱"));
add(new CTCCommands.StrPair("e", "𝗲"));
add(new CTCCommands.StrPair("f", "𝗳"));
add(new CTCCommands.StrPair("g", "𝗴"));
add(new CTCCommands.StrPair("h", "𝗵"));
add(new CTCCommands.StrPair("i", "𝗶"));
add(new CTCCommands.StrPair("j", "𝗷"));
add(new CTCCommands.StrPair("k", "𝗸"));
add(new CTCCommands.StrPair("l", "𝗹"));
add(new CTCCommands.StrPair("m", "𝗺"));
add(new CTCCommands.StrPair("n", "𝗻"));
add(new CTCCommands.StrPair("o", "𝗼"));
add(new CTCCommands.StrPair("p", "𝗽"));
add(new CTCCommands.StrPair("q", "𝗾"));
add(new CTCCommands.StrPair("r", "𝗿"));
add(new CTCCommands.StrPair("s", "𝘀"));
add(new CTCCommands.StrPair("t", "𝘁"));
add(new CTCCommands.StrPair("u", "𝘂"));
add(new CTCCommands.StrPair("v", "𝘃"));
add(new CTCCommands.StrPair("w", "𝘄"));
add(new CTCCommands.StrPair("x", "𝘅"));
add(new CTCCommands.StrPair("y", "𝘆"));
add(new CTCCommands.StrPair("z", "𝘇"));
add(new CTCCommands.StrPair("A", "𝗔"));
add(new CTCCommands.StrPair("B", "𝗕"));
add(new CTCCommands.StrPair("C", "𝗖"));
add(new CTCCommands.StrPair("D", "𝗗"));
add(new CTCCommands.StrPair("E", "𝗘"));
add(new CTCCommands.StrPair("F", "𝗙"));
add(new CTCCommands.StrPair("G", "𝗚"));
add(new CTCCommands.StrPair("H", "𝗛"));
add(new CTCCommands.StrPair("I", "𝗜"));
add(new CTCCommands.StrPair("J", "𝗝"));
add(new CTCCommands.StrPair("K", "𝗞"));
add(new CTCCommands.StrPair("L", "𝗟"));
add(new CTCCommands.StrPair("M", "𝗠"));
add(new CTCCommands.StrPair("N", "𝗡"));
add(new CTCCommands.StrPair("O", "𝗢"));
add(new CTCCommands.StrPair("P", "𝗣"));
add(new CTCCommands.StrPair("Q", "𝗤"));
add(new CTCCommands.StrPair("R", "𝗥"));
add(new CTCCommands.StrPair("S", "𝗦"));
add(new CTCCommands.StrPair("T", "𝗧"));
add(new CTCCommands.StrPair("U", "𝗨"));
add(new CTCCommands.StrPair("V", "𝗩"));
add(new CTCCommands.StrPair("W", "𝗪"));
add(new CTCCommands.StrPair("X", "𝗫"));
add(new CTCCommands.StrPair("Y", "𝗬"));
add(new CTCCommands.StrPair("Z", "𝗭"));
add(new CTCCommands.StrPair("0", "𝟬"));
add(new CTCCommands.StrPair("1", "𝟭"));
add(new CTCCommands.StrPair("2", "𝟮"));
add(new CTCCommands.StrPair("3", "𝟯"));
add(new CTCCommands.StrPair("4", "𝟰"));
add(new CTCCommands.StrPair("5", "𝟱"));
add(new CTCCommands.StrPair("6", "𝟲"));
add(new CTCCommands.StrPair("7", "𝟳"));
add(new CTCCommands.StrPair("8", "𝟴"));
add(new CTCCommands.StrPair("9", "𝟵"));
}};
public static final List<CTCCommands.StrPair> SMALL = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair("a", ""));
add(new CTCCommands.StrPair("b", "ʙ"));
add(new CTCCommands.StrPair("c", ""));
add(new CTCCommands.StrPair("d", ""));
add(new CTCCommands.StrPair("e", ""));
add(new CTCCommands.StrPair("f", ""));
add(new CTCCommands.StrPair("g", "ɢ"));
add(new CTCCommands.StrPair("h", "ʜ"));
add(new CTCCommands.StrPair("i", "ɪ"));
add(new CTCCommands.StrPair("j", ""));
add(new CTCCommands.StrPair("k", ""));
add(new CTCCommands.StrPair("l", "ʟ"));
add(new CTCCommands.StrPair("m", ""));
add(new CTCCommands.StrPair("n", "ɴ"));
add(new CTCCommands.StrPair("o", ""));
add(new CTCCommands.StrPair("p", ""));
add(new CTCCommands.StrPair("q", "ǫ"));
add(new CTCCommands.StrPair("r", "ʀ"));
//add(new CTCCommands.StrPair("s", "s"));
add(new CTCCommands.StrPair("t", ""));
add(new CTCCommands.StrPair("u", ""));
add(new CTCCommands.StrPair("v", ""));
add(new CTCCommands.StrPair("w", ""));
add(new CTCCommands.StrPair("y", "ʏ"));
add(new CTCCommands.StrPair("z", ""));
}};
public static final List<CTCCommands.StrPair> SMALLER = new ArrayList<CTCCommands.StrPair>() {{
add(new CTCCommands.StrPair("a", ""));
add(new CTCCommands.StrPair("b", ""));
add(new CTCCommands.StrPair("c", ""));
add(new CTCCommands.StrPair("d", ""));
add(new CTCCommands.StrPair("e", ""));
add(new CTCCommands.StrPair("f", ""));
add(new CTCCommands.StrPair("g", ""));
add(new CTCCommands.StrPair("h", "ʰ"));
add(new CTCCommands.StrPair("i", ""));
add(new CTCCommands.StrPair("j", "ʲ"));
add(new CTCCommands.StrPair("k", ""));
add(new CTCCommands.StrPair("l", "ˡ"));
add(new CTCCommands.StrPair("m", ""));
add(new CTCCommands.StrPair("n", ""));
add(new CTCCommands.StrPair("o", ""));
add(new CTCCommands.StrPair("p", ""));
add(new CTCCommands.StrPair("q", ""));
add(new CTCCommands.StrPair("r", "ʳ"));
add(new CTCCommands.StrPair("s", "ˢ"));
add(new CTCCommands.StrPair("t", ""));
add(new CTCCommands.StrPair("u", ""));
add(new CTCCommands.StrPair("v", ""));
add(new CTCCommands.StrPair("w", "ʷ"));
add(new CTCCommands.StrPair("x", "ˣ"));
add(new CTCCommands.StrPair("y", "ʸ"));
add(new CTCCommands.StrPair("z", ""));
}};
}

View file

@ -0,0 +1,131 @@
/*package com.cutthecord.commands.commands;
import com.cutthecord.commands.CommandHandler;
import com.discord.stores.StoreStream;
import com.discord.stores.StoreUserSettings;
public class CmdCtc extends CommandHandler.PrivateCommand {
// TODO make token calls write directly to clipboard
// TODO replace patched method calls with reflection
@Override
public String getPopupInfo() {
return "cheese";
}
public static class CmdCtcChannelLeak extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
StoreStream.getUserSettings().setLeakChannels(msg.startsWith("false"));
return "CTC: Successfully set channelleak state.";
}
@Override
public String getPopupInfo() {
return "Shows all channels, even those you dont have permissions to view";
}
}
public static class CmdCtcShowTyping extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
StoreStream.getUserSettings().setShowTyping(msg.startsWith("true"));
return "CTC: Successfully set showtyping state.";
}
@Override
public String getPopupInfo() {
return "Change typing event so that its visible/not when you type";
}
}
public static class CmdCtcToken extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
if (msg.isEmpty()) {
// Print token
return StoreStream.getUserSettings().getStoredToken();
}
// Set token
StoreStream.getUserSettings().setStoredToken(msg);
return "CTC: Successfully changed token. Please restart application.";
}
@Override
public String getPopupInfo() {
return "Gives or sets token";
}
}
public static class CmdCtcAccount extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
String trim = msg.trim();
StoreUserSettings userSettings = StoreStream.getUserSettings();
String accountToken = userSettings.getAccountToken(trim);
if (accountToken.startsWith("none")) {
return "CTC: No such account found.";
}
userSettings.setStoredToken(accountToken);
return "CTC: Successfully changed accounts. Please restart application.";
}
@Override
public String getPopupInfo() {
return "Switches to the account specified";
}
}
public static class CmdCtcAddAccount extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
String substring3 = msg.substring(msg.indexOf(" "));
String trim2 = msg.replace(substring3, "").trim();
String trim3 = substring3.trim();
StoreUserSettings userSettings2 = StoreStream.getUserSettings();
if (trim2.startsWith("current")) {
trim2 = userSettings2.getStoredToken();
}
userSettings2.setAccountToken(trim2, trim3);
return "CTC: Added account.";
}
@Override
public String getPopupInfo() {
return "Adds an account to the account switcher";
}
}
public static class CmdCtcNoDelete extends CommandHandler.PrivateCommand {
@Override
public String handleCommand(String msg) {
StoreStream.getUserSettings().setNoDelete(msg.startsWith("true"));
return "CTC: Successfully set nodelete state.";
}
@Override
public String getPopupInfo() {
return "Disables handling of message delete events";
}
}
}
*/

View file

@ -0,0 +1,44 @@
package com.cutthecord.commands.commands;
import com.cutthecord.commands.RawMsgHandler;
public class CmdEmojify implements RawMsgHandler {
@Override
public String processRawMessage(String msg) {
StringBuilder s = new StringBuilder();
for (char c : msg.toCharArray()) {
s.append(emojifyChar(c));
}
return s.toString();
}
final String[] numbers = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
public String emojifyChar(char c) {
if (Character.isDigit(c)) {
int i = Integer.parseInt(Character.toString(c));
return ":" + numbers[i] + ":";
}
if (Character.isAlphabetic(c)) {
if (c == 'b') {
return ":b:";
}
return ":regional_indicator_" + String.valueOf(c).toLowerCase() + ":";
}
switch (c) {
case '.': return ":record_button";
case '?': return ":grey_question:";
case '!': return ":grey_exclamation:";
}
return Character.toString(c);
}
}

View file

@ -0,0 +1,26 @@
package com.cutthecord.commands.commands;
import com.cutthecord.commands.RawMsgHandler;
public class CmdOwo implements RawMsgHandler {
static final String[] expressions = {
">_<", ":3", "ʕʘ‿ʘʔ", ":D", "._.",
";3", "xD", "ㅇㅅㅇ", "(人◕ω◕)",
">_>", "ÙωÙ", "UwU", "OwO", ":P",
"(◠‿◠✿)", "^_^", ";_;", "XDDD",
"x3", "(• o •)", "<_<", "(・`ω´・)",
";;w;;", ">w<", "^w^"
};
public String processRawMessage(String msg) {
return msg.replaceAll("[rl]", "w")
.replaceAll("[RL]", "W")
.replaceAll("n([aeiou])", "ny$1")
.replaceAll("N([aeiou])", "Ny$1")
.replaceAll("N([AEIOU])", "NY$1")
.replace("ove", "uv")
.replaceAll("!+", " "+ expressions[(int) Math.floor(Math.random()*expressions.length)]+ " ");
}
}

View file

@ -0,0 +1,17 @@
package com.cutthecord.commands.commands;
import com.discord.stores.StoreStream;
public class CmdSpoilerImg {
public String handleCommand(String msg) {
// TODO StoreStream.getUserSettings().setImageSpoiler(true);
return msg;
}
public String getPopupInfo() {
return "Prepends SPOILER_ to names of all images attached to the message that starts with this, causing them to get marked as spoiler";
}
}

View file

@ -48,6 +48,10 @@ with open(os.path.join(REPO_FOLDER, "resources/patchport-state.json")) as f:
VERSION = STATE["versioncode"] VERSION = STATE["versioncode"]
BASE_APK_PATH = os.path.join(WORK_FOLDER, f"discord-base-{VERSION}") BASE_APK_PATH = os.path.join(WORK_FOLDER, f"discord-base-{VERSION}")
BASE_JAR_PATH = os.path.join(WORK_FOLDER, f"discord-base-jar")
# Wipe and recreate the base jar folder
if os.path.exists(BASE_JAR_PATH):
shutil.rmtree(BASE_JAR_PATH)
# Prepare names of input and output APKs # Prepare names of input and output APKs
INPUT_FILE = os.path.join(DISTOK_FOLDER, "android", INPUT_FILE = os.path.join(DISTOK_FOLDER, "android",
@ -79,6 +83,13 @@ if not os.path.exists(BASE_APK_PATH):
shell=True, shell=True,
cwd=WORK_FOLDER) cwd=WORK_FOLDER)
# Convert the dexs to a jar (for slashcommands etc) TODO versionise gradle/this
if not os.path.exists(BASE_JAR_PATH):
subprocess.run(f"unzip -j {INPUT_FILE} *.dex -d {BASE_JAR_PATH}", shell=True, cwd=WORK_FOLDER)
subprocess.run(f"{DEX2JAR_BIN} *.dex", shell=True, cwd=BASE_JAR_PATH)
subprocess.run(f"zipmerge discord-base.jar classes*dex2jar.jar", shell=True, cwd=BASE_JAR_PATH)
subprocess.run(f"rm classes*dex2jar.jar *.dex", shell=True, cwd=BASE_JAR_PATH)
# Copy the base cache to work on it # Copy the base cache to work on it
shutil.copytree(BASE_APK_PATH, WORK_APK_PATH) shutil.copytree(BASE_APK_PATH, WORK_APK_PATH)