First commit
This commit is contained in:
parent
1366a5803c
commit
52ee9f8e53
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,3 +24,5 @@
|
|||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
replay_pid*
|
replay_pid*
|
||||||
|
|
||||||
|
*.env
|
||||||
|
.idea/
|
||||||
|
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
FROM maven:3-eclipse-temurin-22 as build
|
||||||
|
WORKDIR /build
|
||||||
|
COPY --link src src
|
||||||
|
COPY --link pom.xml pom.xml
|
||||||
|
RUN mvn package -DskipTests
|
||||||
|
|
||||||
|
FROM eclipse-temurin:22-jdk-alpine
|
||||||
|
WORKDIR /build
|
||||||
|
COPY --from=build --link /build/target/language-block-bot-*.jar language-block-bot.jar
|
||||||
|
ENTRYPOINT ["java", "-jar", "language-block-bot.jar"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
7
docker-compose.yml
Normal file
7
docker-compose.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
services:
|
||||||
|
language-block-bot:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
JAVA_TOOL_OPTIONS: "-Dlanguageblockbot.bot.token=$TOKEN"
|
167
pom.xml
Normal file
167
pom.xml
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>it.cavallium</groupId>
|
||||||
|
<artifactId>language-block-bot</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|
||||||
|
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
|
||||||
|
<maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
|
||||||
|
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<url>https://repo.maven.apache.org/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains</groupId>
|
||||||
|
<artifactId>annotations</artifactId>
|
||||||
|
<version>24.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
|
<version>7.2.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jetbrains</groupId>
|
||||||
|
<artifactId>annotations</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-longpolling</artifactId>
|
||||||
|
<version>7.2.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-client</artifactId>
|
||||||
|
<version>7.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pemistahl</groupId>
|
||||||
|
<artifactId>lingua</artifactId>
|
||||||
|
<version>1.2.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.squareup.okio</groupId>
|
||||||
|
<artifactId>okio</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jdk14</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven-compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>${maven-shade-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
|
<version>3.0.0-M3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>enforce</id>
|
||||||
|
<configuration>
|
||||||
|
<rules>
|
||||||
|
<dependencyConvergence/>
|
||||||
|
</rules>
|
||||||
|
</configuration>
|
||||||
|
<goals>
|
||||||
|
<goal>enforce</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>it.cavallium.languageblockbot.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,152 @@
|
|||||||
|
package it.cavallium.languageblockbot;
|
||||||
|
|
||||||
|
import com.github.pemistahl.lingua.api.Language;
|
||||||
|
import com.github.pemistahl.lingua.api.LanguageDetector;
|
||||||
|
import com.github.pemistahl.lingua.api.LanguageDetectorBuilder;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.telegram.telegrambots.abilitybots.api.bot.AbilityBot;
|
||||||
|
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
|
||||||
|
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMember;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.message.Message;
|
||||||
|
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||||
|
|
||||||
|
public class LanguageBlockBot extends AbilityBot {
|
||||||
|
|
||||||
|
private final LanguageDetector detector;
|
||||||
|
private final ConcurrentMap<Long, Set<Long>> chatAdmins = new ConcurrentHashMap<>();
|
||||||
|
private final Set<Language> whitelistedLangs;
|
||||||
|
private final Set<Language> blacklistedLangs;
|
||||||
|
|
||||||
|
public LanguageBlockBot(String token, Set<Language> whitelistedLangs, Set<Language> blacklistedLangs) {
|
||||||
|
super(new org.telegram.telegrambots.client.okhttp.OkHttpTelegramClient(token), "LanguageBlockBot");
|
||||||
|
|
||||||
|
var allLangs = new HashSet<Language>();
|
||||||
|
allLangs.addAll(whitelistedLangs);
|
||||||
|
allLangs.addAll(blacklistedLangs);
|
||||||
|
this.detector = LanguageDetectorBuilder.fromLanguages(allLangs.toArray(Language[]::new))
|
||||||
|
.withPreloadedLanguageModels()
|
||||||
|
.withMinimumRelativeDistance(0.8)
|
||||||
|
.build();
|
||||||
|
this.whitelistedLangs = whitelistedLangs;
|
||||||
|
this.blacklistedLangs = blacklistedLangs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consume(Update update) {
|
||||||
|
if (update.hasMessage()) {
|
||||||
|
var msg = update.getMessage();
|
||||||
|
String text;
|
||||||
|
if (msg.hasText()) {
|
||||||
|
text = msg.getText();
|
||||||
|
} else if (msg.getCaption() != null) {
|
||||||
|
text = msg.getCaption();
|
||||||
|
} else {
|
||||||
|
text = null;
|
||||||
|
}
|
||||||
|
if (text != null) {
|
||||||
|
var detectedLangs = detector.computeLanguageConfidenceValues(text);
|
||||||
|
double acceptableLanguageValue = whitelistedLangs
|
||||||
|
.stream()
|
||||||
|
.map(whitelistedLang -> detectedLangs.getOrDefault(whitelistedLang, 0.0))
|
||||||
|
.reduce(Math::max)
|
||||||
|
.orElse(0d);
|
||||||
|
double blacklistedLanguageValue = blacklistedLangs
|
||||||
|
.stream()
|
||||||
|
.map(blacklistedLang -> detectedLangs.getOrDefault(blacklistedLang, 0.0))
|
||||||
|
.reduce(Math::max)
|
||||||
|
.orElse(0d);
|
||||||
|
|
||||||
|
var shouldBeDeletedByLanguage = !detectedLangs.isEmpty() &&
|
||||||
|
(acceptableLanguageValue <= 0.75
|
||||||
|
|| (acceptableLanguageValue < blacklistedLanguageValue));
|
||||||
|
|
||||||
|
System.out.printf("Received message: \"%s\". shouldBeDeletedByLanguage: %b. Languages: \"%s\".%n",
|
||||||
|
text,
|
||||||
|
shouldBeDeletedByLanguage,
|
||||||
|
detectedLangs.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(", ", "[", "]"))
|
||||||
|
);
|
||||||
|
if (shouldBeDeletedByLanguage) {
|
||||||
|
isMessageDeletable(msg).thenCompose(deletable -> {
|
||||||
|
var deleteMessageMethod = DeleteMessage
|
||||||
|
.builder()
|
||||||
|
.chatId(msg.getChatId())
|
||||||
|
.messageId(msg.getMessageId())
|
||||||
|
.build();
|
||||||
|
try {
|
||||||
|
var client = this.getTelegramClient();
|
||||||
|
return client.executeAsync(deleteMessageMethod);
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
return CompletableFuture.failedFuture(e);
|
||||||
|
}
|
||||||
|
}).whenComplete((ok, ex) -> {
|
||||||
|
if (ex != null) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Boolean> isMessageDeletable(Message msg) {
|
||||||
|
var chatId = msg.getChatId();
|
||||||
|
CompletableFuture<Boolean> canDeleteBecauseItsNotAdmin;
|
||||||
|
if (msg.getSenderChat() != null) {
|
||||||
|
canDeleteBecauseItsNotAdmin = getChatAdmins(chatId)
|
||||||
|
.thenApply(admins -> !admins.contains(msg.getSenderChat().getId()));
|
||||||
|
} else {
|
||||||
|
canDeleteBecauseItsNotAdmin = CompletableFuture.completedFuture(true);
|
||||||
|
}
|
||||||
|
boolean canDeleteBecauseItsNormalMessage = !(msg.getIsAutomaticForward() != null && msg.getIsAutomaticForward())
|
||||||
|
&& (msg.getSenderChat() != null && msg.getSenderChat().isUserChat()) && !msg.hasViaBot();
|
||||||
|
|
||||||
|
return CompletableFuture
|
||||||
|
.completedFuture(canDeleteBecauseItsNormalMessage)
|
||||||
|
.thenCombine(canDeleteBecauseItsNotAdmin, (a, b) -> a && b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Set<Long>> getChatAdmins(Long chatId) {
|
||||||
|
var client = this.getTelegramClient();
|
||||||
|
if (chatId >= 0) {
|
||||||
|
return CompletableFuture.completedFuture(Set.of());
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
var cachedAdmins = this.chatAdmins.get(chatId);
|
||||||
|
if (cachedAdmins != null) {
|
||||||
|
return CompletableFuture.completedFuture(cachedAdmins);
|
||||||
|
} else {
|
||||||
|
return client
|
||||||
|
.executeAsync(GetChatAdministrators.builder().chatId(chatId).build())
|
||||||
|
.<List<ChatMember>>handle((result, err) -> {
|
||||||
|
if (err != null) {
|
||||||
|
err.printStackTrace();
|
||||||
|
return List.of();
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.thenApply(admins -> {
|
||||||
|
var newAdmins = admins.stream().map(n -> n.getUser().getId()).collect(Collectors.toCollection(HashSet<Long>::new));
|
||||||
|
chatAdmins.put(chatId, newAdmins);
|
||||||
|
return newAdmins;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long creatorId() {
|
||||||
|
return 40951146;
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/it/cavallium/languageblockbot/Main.java
Normal file
39
src/main/java/it/cavallium/languageblockbot/Main.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package it.cavallium.languageblockbot;
|
||||||
|
|
||||||
|
import com.github.pemistahl.lingua.api.Language;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.telegram.telegrambots.longpolling.TelegramBotsLongPollingApplication;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String token = System.getProperty("languageblockbot.bot.token", "invalid-token");
|
||||||
|
Set<Language> whitelistedLangs;
|
||||||
|
Set<Language> blacklistedLangs;
|
||||||
|
try {
|
||||||
|
whitelistedLangs = Stream
|
||||||
|
.of(System.getProperty("languageblockbot.langs.whitelisted", "ENGLISH,FRENCH,ITALIAN").split(","))
|
||||||
|
.map(Language::valueOf)
|
||||||
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
blacklistedLangs = Stream
|
||||||
|
.of(System.getProperty("languageblockbot.langs.blacklisted", "SOMALI,ARABIC,RUSSIAN,UKRAINIAN,CHINESE,AZERBAIJANI,SPANISH,PORTUGUESE,HINDI,POLISH,VIETNAMESE").split(","))
|
||||||
|
.map(Language::valueOf)
|
||||||
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
System.err.println("Invalid language value. Allowed values: " + Arrays.toString(Language.values()));
|
||||||
|
ex.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try (var app = new TelegramBotsLongPollingApplication()) {
|
||||||
|
var bot = new LanguageBlockBot(token, whitelistedLangs, blacklistedLangs);
|
||||||
|
bot.onRegister();
|
||||||
|
app.registerBot(token, bot);
|
||||||
|
Thread.currentThread().join();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user