mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-25 04:27:41 +08:00
scala port stage2 (not tested)
This commit is contained in:
parent
aafdcc1fb2
commit
1a31a22cd9
@ -99,8 +99,8 @@ scala {
|
|||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
|
|
||||||
sourceCompatibility '17'
|
sourceCompatibility proj_java.getMajorVersion()
|
||||||
targetCompatibility '17'
|
targetCompatibility proj_java.getMajorVersion()
|
||||||
|
|
||||||
options.encoding = proj_file_encoding.name()
|
options.encoding = proj_file_encoding.name()
|
||||||
|
|
||||||
@ -108,9 +108,14 @@ scala {
|
|||||||
|
|
||||||
compileScala {
|
compileScala {
|
||||||
|
|
||||||
|
sourceCompatibility proj_java.getMajorVersion()
|
||||||
|
targetCompatibility proj_java.getMajorVersion()
|
||||||
|
|
||||||
options.encoding = proj_file_encoding.name()
|
options.encoding = proj_file_encoding.name()
|
||||||
scalaCompileOptions.encoding = proj_file_encoding.name()
|
scalaCompileOptions.encoding = proj_file_encoding.name()
|
||||||
|
|
||||||
|
// scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s
|
|||||||
VERSION = 1.0.0-RC4
|
VERSION = 1.0.0-RC4
|
||||||
|
|
||||||
USE_DELTA = true
|
USE_DELTA = true
|
||||||
VERSION_DELTA = scalaport1
|
VERSION_DELTA = scalaport2
|
||||||
|
|
||||||
CODENAME = beiping
|
CODENAME = beiping
|
||||||
|
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -5,6 +5,7 @@ import cc.sukazyo.messiva.log.LogLevel;
|
|||||||
import cc.sukazyo.messiva.logger.Logger;
|
import cc.sukazyo.messiva.logger.Logger;
|
||||||
import cc.sukazyo.messiva.appender.ConsoleAppender;
|
import cc.sukazyo.messiva.appender.ConsoleAppender;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ public class Log {
|
|||||||
* @return {@link String} 格式的异常的堆栈报告信息.
|
* @return {@link String} 格式的异常的堆栈报告信息.
|
||||||
* @see 1.0.0-alpha5
|
* @see 1.0.0-alpha5
|
||||||
*/
|
*/
|
||||||
public static String exceptionLog (Exception e) {
|
public static String exceptionLog (@Nonnull Throwable e) {
|
||||||
final StringWriter stackTrace = new StringWriter();
|
final StringWriter stackTrace = new StringWriter();
|
||||||
e.printStackTrace(new PrintWriter(stackTrace));
|
e.printStackTrace(new PrintWriter(stackTrace));
|
||||||
return stackTrace.toString();
|
return stackTrace.toString();
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package cc.sukazyo.cono.morny;
|
package cc.sukazyo.cono.morny;
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.OnUpdate;
|
import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener$;
|
||||||
import cc.sukazyo.cono.morny.bot.command.MornyCommands;
|
import cc.sukazyo.cono.morny.bot.command.MornyCommands;
|
||||||
import cc.sukazyo.cono.morny.bot.event.EventListeners;
|
import cc.sukazyo.cono.morny.bot.event.MornyEventListeners;
|
||||||
import cc.sukazyo.cono.morny.bot.query.MornyQueries;
|
import cc.sukazyo.cono.morny.bot.query.MornyQueries;
|
||||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
||||||
import cc.sukazyo.cono.morny.daemon.TrackerDataManager;
|
import cc.sukazyo.cono.morny.daemon.TrackerDataManager;
|
||||||
@ -31,8 +31,6 @@ public class MornyCoeur {
|
|||||||
|
|
||||||
/** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */
|
/** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */
|
||||||
private final MornyTrusted trusted;
|
private final MornyTrusted trusted;
|
||||||
/** 当前 Morny 的 telegram 命令管理器 */
|
|
||||||
private final MornyCommands commandManager = new MornyCommands();
|
|
||||||
private final MornyQueries queryManager = new MornyQueries();
|
private final MornyQueries queryManager = new MornyQueries();
|
||||||
|
|
||||||
/** morny 的 bot 账户 */
|
/** morny 的 bot 账户 */
|
||||||
@ -127,12 +125,12 @@ public class MornyCoeur {
|
|||||||
MornyDaemons.start();
|
MornyDaemons.start();
|
||||||
|
|
||||||
logger.info("start telegram events listening");
|
logger.info("start telegram events listening");
|
||||||
EventListeners.registerAllListeners();
|
MornyEventListeners.registerAllEvents();
|
||||||
INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate);
|
INSTANCE.account.setUpdatesListener(TelegramUpdatesListener$.MODULE$);
|
||||||
|
|
||||||
if (config.commandLoginRefresh) {
|
if (config.commandLoginRefresh) {
|
||||||
logger.info("resetting telegram command list");
|
logger.info("resetting telegram command list");
|
||||||
commandManager().automaticUpdateList();
|
MornyCommands.automaticTGListUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Coeur start complete");
|
logger.info("Coeur start complete");
|
||||||
@ -156,7 +154,7 @@ public class MornyCoeur {
|
|||||||
private void exitCleanup () {
|
private void exitCleanup () {
|
||||||
MornyDaemons.stop();
|
MornyDaemons.stop();
|
||||||
if (config.commandLogoutClear) {
|
if (config.commandLogoutClear) {
|
||||||
commandManager.automaticRemoveList();
|
MornyCommands.automaticTGListRemove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,11 +286,6 @@ public class MornyCoeur {
|
|||||||
return INSTANCE.trusted;
|
return INSTANCE.trusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public static MornyCommands commandManager () {
|
|
||||||
return INSTANCE.commandManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static MornyQueries queryManager () {
|
public static MornyQueries queryManager () {
|
||||||
return INSTANCE.queryManager;
|
return INSTANCE.queryManager;
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.api;
|
|
||||||
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public abstract class EventListener {
|
|
||||||
|
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onEditedMessage (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onChannelPost (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onInlineQuery (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onChosenInlineResult (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onCallbackQuery (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onShippingQuery (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onPreCheckoutQuery (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onPoll (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onPollAnswer (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onMyChatMemberUpdated (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onChatMemberUpdated (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onChatJoinRequest (@Nonnull Update update) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.api;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.Log;
|
|
||||||
import cc.sukazyo.cono.morny.daemon.MornyReport;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.Log.logger;
|
|
||||||
|
|
||||||
public class EventListenerManager {
|
|
||||||
|
|
||||||
private static final List<EventListener> listeners = new ArrayList<>();
|
|
||||||
|
|
||||||
private static class EventPublisher extends Thread {
|
|
||||||
|
|
||||||
private final Function<EventListener, Boolean> exec;
|
|
||||||
|
|
||||||
public EventPublisher(@Nonnull Update update, @Nonnull Function<EventListener, Boolean> exec) {
|
|
||||||
this.setName("EVT"+update.updateId());
|
|
||||||
this.exec = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run () {
|
|
||||||
for (EventListener x : listeners) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (exec.apply(x)) return;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
final StringBuilder errorMessage = new StringBuilder();
|
|
||||||
errorMessage.append("Event throws unexpected exception:\n");
|
|
||||||
errorMessage.append(Log.exceptionLog(e).indent(4));
|
|
||||||
if (e instanceof EventRuntimeException.ActionFailed) {
|
|
||||||
errorMessage.append("\ntg-api action: response track: ");
|
|
||||||
errorMessage.append(new GsonBuilder().setPrettyPrinting().create().toJson(
|
|
||||||
((EventRuntimeException.ActionFailed)e).getResponse()
|
|
||||||
).indent(4)).append('\n');
|
|
||||||
}
|
|
||||||
logger.error(errorMessage.toString());
|
|
||||||
|
|
||||||
MornyReport.exception(e, "on event running");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addListener (@Nonnull EventListener... listeners) {
|
|
||||||
EventListenerManager.listeners.addAll(Arrays.asList(listeners));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishMessageEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onMessage(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishEditedMessageEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onEditedMessage(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishChannelPostEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onChannelPost(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishEditedChannelPostEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onEditedChannelPost(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishInlineQueryEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onInlineQuery(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishChosenInlineResultEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onChosenInlineResult(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishCallbackQueryEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onCallbackQuery(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishShippingQueryEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onShippingQuery(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishPreCheckoutQueryEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onPreCheckoutQuery(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishPollEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onPoll(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishPollAnswerEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onPollAnswer(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishMyChatMemberUpdatedEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onMyChatMemberUpdated(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishChatMemberUpdatedEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onChatMemberUpdated(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void publishChatJoinRequestEvent (@Nonnull Update update) {
|
|
||||||
new EventPublisher(update, x -> x.onChatJoinRequest(update)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.api;
|
|
||||||
|
|
||||||
import com.pengrad.telegrambot.model.request.InlineQueryResult;
|
|
||||||
|
|
||||||
public class InlineQueryUnit<T extends InlineQueryResult<T>> {
|
|
||||||
|
|
||||||
public static final int DEFAULT_INLINE_CACHE_TIME = 300;
|
|
||||||
public static final boolean DEFAULT_INLINE_PERSONAL_RESP = false;
|
|
||||||
|
|
||||||
private int cacheTime = DEFAULT_INLINE_CACHE_TIME;
|
|
||||||
private boolean isPersonal = DEFAULT_INLINE_PERSONAL_RESP;
|
|
||||||
public final T result;
|
|
||||||
|
|
||||||
public InlineQueryUnit (T result) {
|
|
||||||
this.result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int cacheTime () {
|
|
||||||
return cacheTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InlineQueryUnit<T> cacheTime (int cacheTime) {
|
|
||||||
this.cacheTime = cacheTime;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPersonal () {
|
|
||||||
return isPersonal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InlineQueryUnit<T> isPersonal (boolean isPersonal) {
|
|
||||||
this.isPersonal = isPersonal;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.api;
|
|
||||||
|
|
||||||
import com.pengrad.telegrambot.UpdatesListener;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class OnUpdate {
|
|
||||||
|
|
||||||
public static int onNormalUpdate (@Nonnull List<Update> updates) {
|
|
||||||
for (Update update : updates) {
|
|
||||||
if (update.message() != null) {
|
|
||||||
EventListenerManager.publishMessageEvent(update);
|
|
||||||
}
|
|
||||||
if (update.editedMessage() != null) {
|
|
||||||
EventListenerManager.publishEditedMessageEvent(update);
|
|
||||||
}
|
|
||||||
if (update.channelPost() != null) {
|
|
||||||
EventListenerManager.publishChannelPostEvent(update);
|
|
||||||
}
|
|
||||||
if (update.editedChannelPost() != null) {
|
|
||||||
EventListenerManager.publishEditedChannelPostEvent(update);
|
|
||||||
}
|
|
||||||
if (update.inlineQuery() != null) {
|
|
||||||
EventListenerManager.publishInlineQueryEvent(update);
|
|
||||||
}
|
|
||||||
if (update.chosenInlineResult() != null) {
|
|
||||||
EventListenerManager.publishChosenInlineResultEvent(update);
|
|
||||||
}
|
|
||||||
if (update.callbackQuery() != null) {
|
|
||||||
EventListenerManager.publishCallbackQueryEvent(update);
|
|
||||||
}
|
|
||||||
if (update.shippingQuery() != null) {
|
|
||||||
EventListenerManager.publishShippingQueryEvent(update);
|
|
||||||
}
|
|
||||||
if (update.preCheckoutQuery() != null) {
|
|
||||||
EventListenerManager.publishPreCheckoutQueryEvent(update);
|
|
||||||
}
|
|
||||||
if (update.poll() != null) {
|
|
||||||
EventListenerManager.publishPollEvent(update);
|
|
||||||
}
|
|
||||||
if (update.pollAnswer() != null) {
|
|
||||||
EventListenerManager.publishPollAnswerEvent(update);
|
|
||||||
}
|
|
||||||
if (update.myChatMember() != null) {
|
|
||||||
EventListenerManager.publishMyChatMemberUpdatedEvent(update);
|
|
||||||
}
|
|
||||||
if (update.chatMember() != null) {
|
|
||||||
EventListenerManager.publishChatMemberUpdatedEvent(update);
|
|
||||||
}
|
|
||||||
if (update.chatJoinRequest() != null) {
|
|
||||||
EventListenerManager.publishChatJoinRequestEvent(update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UpdatesListener.CONFIRMED_UPDATES_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public interface ISimpleCommand {
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
String getName();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
String[] getAliases();
|
|
||||||
|
|
||||||
void execute (@Nonnull InputCommand command, @Nonnull Update event);
|
|
||||||
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
public interface ITelegramCommand extends ISimpleCommand {
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
String getParamRule();
|
|
||||||
@Nonnull
|
|
||||||
String getDescription();
|
|
||||||
|
|
||||||
}
|
|
@ -1,297 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.event.OnUniMeowTrigger;
|
|
||||||
import cc.sukazyo.cono.morny.daemon.MornyReport;
|
|
||||||
import cc.sukazyo.cono.morny.data.MornyJrrp;
|
|
||||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString;
|
|
||||||
import com.pengrad.telegrambot.model.BotCommand;
|
|
||||||
import com.pengrad.telegrambot.model.DeleteMyCommands;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
|
||||||
import com.pengrad.telegrambot.request.SendMessage;
|
|
||||||
import com.pengrad.telegrambot.request.SendSticker;
|
|
||||||
import com.pengrad.telegrambot.request.SetMyCommands;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.Log.logger;
|
|
||||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
|
||||||
|
|
||||||
public class MornyCommands {
|
|
||||||
|
|
||||||
private final Map<String, ISimpleCommand> commands = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
private void pushCommandTo (@Nonnull String name, @Nonnull ISimpleCommand instance) {
|
|
||||||
if (commands.containsKey(name)) {
|
|
||||||
logger.warn(String.format("""
|
|
||||||
Telegram command instance named "%s" already exists and will be override by another command instance
|
|
||||||
- current: %s
|
|
||||||
- new : %s""",
|
|
||||||
name,
|
|
||||||
commands.get(name).getClass().getName(),
|
|
||||||
instance.getClass().getName()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
commands.put(name, instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register (@Nonnull ISimpleCommand... list) {
|
|
||||||
for (ISimpleCommand instance : list) {
|
|
||||||
final String[] aliases = instance.getAliases();
|
|
||||||
pushCommandTo(instance.getName(), instance);
|
|
||||||
if (aliases!=null) for (String alias : aliases) pushCommandTo(alias, instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("NonAsciiCharacters")
|
|
||||||
public MornyCommands () {
|
|
||||||
|
|
||||||
register(
|
|
||||||
new ON(),
|
|
||||||
new Hello(), /* new {@link HelloOnStart}, */
|
|
||||||
MornyInformation$.MODULE$,
|
|
||||||
GetUsernameAndId$.MODULE$,
|
|
||||||
EventHack$.MODULE$,
|
|
||||||
Nbnhhsh$.MODULE$,
|
|
||||||
IP186Query.IP$.MODULE$,
|
|
||||||
IP186Query.Whois$.MODULE$,
|
|
||||||
Encryptor$.MODULE$,
|
|
||||||
new SaveData(),
|
|
||||||
MornyInfoOnHello$.MODULE$,
|
|
||||||
new Version(),
|
|
||||||
new MornyRuntime(),
|
|
||||||
new Jrrp(),
|
|
||||||
new Exit(), new ExitAlias()
|
|
||||||
);
|
|
||||||
|
|
||||||
// 特殊的命令
|
|
||||||
register(
|
|
||||||
Testing$.MODULE$,
|
|
||||||
DirectMsgClear$.MODULE$
|
|
||||||
);
|
|
||||||
|
|
||||||
// 统一注册这些奇怪的东西&.&
|
|
||||||
register(
|
|
||||||
私わね$.MODULE$,
|
|
||||||
喵呜.Progynova$.MODULE$
|
|
||||||
);
|
|
||||||
// special: 注册出于兼容使用的特别 event 的数据
|
|
||||||
OnUniMeowTrigger.register(
|
|
||||||
喵呜.抱抱$.MODULE$,
|
|
||||||
喵呜.揉揉$.MODULE$,
|
|
||||||
喵呜.蹭蹭$.MODULE$,
|
|
||||||
喵呜.贴贴$.MODULE$
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
|
||||||
if (commands.containsKey(command.getCommand())) {
|
|
||||||
commands.get(command.getCommand()).execute(command, event);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return nonCommandExecutable(event, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void automaticUpdateList () {
|
|
||||||
BotCommand[] commandList = getCommandListTelegram();
|
|
||||||
automaticRemoveList();
|
|
||||||
MornyCoeur.extra().exec(new SetMyCommands(
|
|
||||||
commandList
|
|
||||||
));
|
|
||||||
logger.info("automatic updated telegram command list :\n" + commandListToString(commandList));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void automaticRemoveList () {
|
|
||||||
MornyCoeur.extra().exec(new DeleteMyCommands());
|
|
||||||
logger.info("cleaned up command list.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String commandListToString (@Nonnull BotCommand[] list) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (BotCommand signal : list) {
|
|
||||||
builder.append(signal.command()).append(" - ").append(signal.description()).append("\n");
|
|
||||||
}
|
|
||||||
return builder.substring(0, builder.length()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BotCommand[] getCommandListTelegram () {
|
|
||||||
final List<BotCommand> telegramFormatListing = new ArrayList<>();
|
|
||||||
commands.forEach((regKey, command) -> {
|
|
||||||
if (command instanceof ITelegramCommand && regKey.equals(command.getName())) {
|
|
||||||
telegramFormatListing.add(formatTelegramCommandListLine(
|
|
||||||
command.getName(),
|
|
||||||
((ITelegramCommand)command).getParamRule(),
|
|
||||||
((ITelegramCommand)command).getDescription()
|
|
||||||
));
|
|
||||||
if (command.getAliases() != null) for (String alias : command.getAliases()) {
|
|
||||||
telegramFormatListing.add(formatTelegramCommandListLine(alias, "", "↑"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return telegramFormatListing.toArray(BotCommand[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BotCommand formatTelegramCommandListLine (@Nonnull String commandName, @Nonnull String paramRule, @Nonnull String intro) {
|
|
||||||
return new BotCommand(commandName, paramRule.isEmpty() ? (intro) : (paramRule+" - "+intro));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean nonCommandExecutable (Update event, InputCommand command) {
|
|
||||||
if (command.getTarget() == null) return false; // 无法解析的命令,转交事件链后代处理
|
|
||||||
else { // 无法解析的显式命令格式,报错找不到命令
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_404
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// /// /// /// /// /// /// /// ///
|
|
||||||
///
|
|
||||||
/// Old Simple Command Block
|
|
||||||
///
|
|
||||||
|
|
||||||
private static class ON implements ITelegramCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "o"; }
|
|
||||||
@Nullable
|
|
||||||
@Override public String[] getAliases () { return null; }
|
|
||||||
@Nonnull @Override public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Override public String getDescription () { return "检查是否在线"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandOnExec(event); }
|
|
||||||
}
|
|
||||||
private static void onCommandOnExec (@Nonnull Update event) {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_ONLINE_STATUS_RETURN
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Hello implements ITelegramCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "hello"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return new String[]{"hi"}; }
|
|
||||||
@Nonnull @Override public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Override public String getDescription () { return "打招呼"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); }
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* {@link Hello} on special command /start
|
|
||||||
* Deprecated due to new {@link MornyInfoOnHello}
|
|
||||||
*/
|
|
||||||
@Deprecated @SuppressWarnings("unused")
|
|
||||||
private static class HelloOnStart implements ISimpleCommand { @Nonnull @Override public String getName () { return "start"; }@Nullable @Override public String[] getAliases () { return new String[0]; }@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); }}
|
|
||||||
private static void onCommandHelloExec (@Nonnull Update event) {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_HELLO
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Exit implements ITelegramCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "exit"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return new String[0]; }
|
|
||||||
@Nonnull @Override public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Override public String getDescription () { return "关闭 Bot (仅可信成员)"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); }
|
|
||||||
}
|
|
||||||
private static class ExitAlias implements ISimpleCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "quit"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return new String[]{"stop"}; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); }
|
|
||||||
}
|
|
||||||
private static void onCommandExitExec (@Nonnull Update event) {
|
|
||||||
if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_EXIT
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
logger.info("Morny exited by user " + TGToString.as(event.message().from()).toStringLogTag());
|
|
||||||
MornyCoeur.exit(0, event.message().from());
|
|
||||||
} else {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_403
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
logger.info("403 exited tag from user " + TGToString.as(event.message().from()).toStringLogTag());
|
|
||||||
MornyReport.unauthenticatedAction("/exit", event.message().from());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Version implements ISimpleCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "version"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return null; }
|
|
||||||
@Nonnull @Deprecated public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Deprecated public String getDescription () { return "检查 Bot 版本信息"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoVersion(event); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MornyRuntime implements ISimpleCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "runtime"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return null; }
|
|
||||||
@Nonnull @Deprecated public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Deprecated public String getDescription () { return "获取 Bot 运行时信息(包括版本号)"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoRuntime(event); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Jrrp implements ITelegramCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "jrrp"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return null; }
|
|
||||||
@Nonnull @Override public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Override public String getDescription () { return "获取 (假的) jrrp"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandJrrpExec(event); }
|
|
||||||
}
|
|
||||||
private static void onCommandJrrpExec (Update event) {
|
|
||||||
final double jrrp = MornyJrrp.getJrrpFromTelegramUser(event.message().from(), System.currentTimeMillis());
|
|
||||||
final String endChar = jrrp>70 ? "!" : jrrp>30 ? ";" : "...";
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
event.message().chat().id(),
|
|
||||||
String.format(
|
|
||||||
"%s 在(utc的)今天的运气指数是———— <code>%.2f%%</code> %s",
|
|
||||||
TGToString.as(event.message().from()).fullnameRefHtml(),
|
|
||||||
jrrp, escapeHtml(endChar)
|
|
||||||
)
|
|
||||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class SaveData implements ITelegramCommand {
|
|
||||||
@Nonnull @Override public String getName () { return "save"; }
|
|
||||||
@Nullable @Override public String[] getAliases () { return null; }
|
|
||||||
@Nonnull @Override public String getParamRule () { return ""; }
|
|
||||||
@Nonnull @Override public String getDescription () { return "保存缓存数据到文件(仅可信成员)"; }
|
|
||||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onSaveDataExec(event); }
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @since 0.4.3.0
|
|
||||||
*/
|
|
||||||
private static void onSaveDataExec (Update event) {
|
|
||||||
if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
|
|
||||||
logger.info("called save from command by " + TGToString.as(event.message().from()).toStringLogTag());
|
|
||||||
MornyCoeur.callSaveData();
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_SAVED
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
event.message().chat().id(),
|
|
||||||
TelegramStickers.ID_403
|
|
||||||
).replyToMessageId(event.message().messageId())
|
|
||||||
);
|
|
||||||
logger.info("403 call save tag from user " + TGToString.as(event.message().from()).toStringLogTag());
|
|
||||||
MornyReport.unauthenticatedAction("/save", event.message().from());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListenerManager;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
|
||||||
|
|
||||||
public class EventListeners {
|
|
||||||
|
|
||||||
public static final OnTelegramCommand COMMANDS_LISTENER = new OnTelegramCommand();
|
|
||||||
// public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
|
|
||||||
public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock();
|
|
||||||
public static final OnEventHackHandle EVENT_HACK_HANDLE = new OnEventHackHandle();
|
|
||||||
// static final OnKuohuanhuanNeedSleep KUOHUANHUAN_NEED_SLEEP = new OnKuohuanhuanNeedSleep();
|
|
||||||
public static final OnCallMsgSend CALL_MSG_SEND = new OnCallMsgSend();
|
|
||||||
public static final OnMedicationNotifyApply MEDICATION_NOTIFY_APPLY = new OnMedicationNotifyApply();
|
|
||||||
public static final OnRandomlyTriggered RANDOMLY_TRIGGERED = new OnRandomlyTriggered();
|
|
||||||
public static final OnUniMeowTrigger UNI_MEOW_TRIGGER = new OnUniMeowTrigger();
|
|
||||||
public static final OnQuestionMarkReply QUESTION_MARK_REPLY = new OnQuestionMarkReply();
|
|
||||||
|
|
||||||
public static void registerAllListeners () {
|
|
||||||
EventListenerManager.addListener(
|
|
||||||
// ACTIVITY_RECORDER,
|
|
||||||
UPDATE_TIMESTAMP_OFFSET_LOCK,
|
|
||||||
/* write functional event behind here */
|
|
||||||
// KUOHUANHUAN_NEED_SLEEP,
|
|
||||||
COMMANDS_LISTENER,
|
|
||||||
UNI_MEOW_TRIGGER,
|
|
||||||
RANDOMLY_TRIGGERED,
|
|
||||||
OnUserRandom$.MODULE$,
|
|
||||||
QUESTION_MARK_REPLY,
|
|
||||||
OnUserSlashAction$.MODULE$,
|
|
||||||
OnInlineQuery$.MODULE$,
|
|
||||||
OnCallMe$.MODULE$,
|
|
||||||
CALL_MSG_SEND,
|
|
||||||
MEDICATION_NOTIFY_APPLY,
|
|
||||||
EVENT_HACK_HANDLE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -8,7 +8,7 @@ import com.pengrad.telegrambot.model.Update;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class OnActivityRecord extends EventListener {
|
public class OnActivityRecord implements EventListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
public boolean onMessage (@Nonnull Update update) {
|
||||||
@ -22,7 +22,7 @@ public class OnActivityRecord extends EventListener {
|
|||||||
(long)update.message().date() * 1000
|
(long)update.message().date() * 1000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return super.onMessage(update);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,222 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.pengrad.telegrambot.model.Chat;
|
|
||||||
import com.pengrad.telegrambot.model.Message;
|
|
||||||
import com.pengrad.telegrambot.model.MessageEntity;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
|
||||||
import com.pengrad.telegrambot.request.GetChat;
|
|
||||||
import com.pengrad.telegrambot.request.SendMessage;
|
|
||||||
import com.pengrad.telegrambot.request.SendSticker;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
|
||||||
import com.pengrad.telegrambot.response.GetChatResponse;
|
|
||||||
import com.pengrad.telegrambot.response.SendResponse;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
|
||||||
|
|
||||||
|
|
||||||
public class OnCallMsgSend extends EventListener {
|
|
||||||
|
|
||||||
private static final Pattern REGEX_MSG_SENDREQ_DATA_HEAD = Pattern.compile("^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$");
|
|
||||||
|
|
||||||
private record MessageToSend (
|
|
||||||
@Nullable String message,
|
|
||||||
@Nullable MessageEntity[] entities,
|
|
||||||
@Nullable ParseMode parseMode,
|
|
||||||
long targetId
|
|
||||||
) { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage(@Nonnull Update update) {
|
|
||||||
|
|
||||||
// 执行体检查
|
|
||||||
if (update.message().chat().type() != Chat.Type.Private) return false;
|
|
||||||
if (update.message().text() == null) return false;
|
|
||||||
if (!update.message().text().startsWith("*msg")) return false;
|
|
||||||
|
|
||||||
// 权限检查
|
|
||||||
if (!MornyCoeur.trustedInstance().isTrusted(update.message().from().id())) {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
update.message().chat().id(),
|
|
||||||
TelegramStickers.ID_403
|
|
||||||
).replyToMessageId(update.message().messageId()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Message msgsendReqRaw; // 用户书写的发送请求原文
|
|
||||||
MessageToSend msgsendReqBody; // 解析后的发送请求实例
|
|
||||||
|
|
||||||
// *msgsend 发送标识
|
|
||||||
// 处理发送要求
|
|
||||||
if (update.message().text().equals("*msgsend")) {
|
|
||||||
// 发送体处理
|
|
||||||
if (update.message().replyToMessage() == null) return answer404(update);
|
|
||||||
msgsendReqBody = parseRequest(update.message().replyToMessage());
|
|
||||||
if (msgsendReqBody == null || msgsendReqBody.message == null) return answer404(update);
|
|
||||||
// 执行发送任务
|
|
||||||
SendResponse sendResponse = MornyCoeur.getAccount().execute(parseMessageToSend(msgsendReqBody));
|
|
||||||
if (!sendResponse.isOk()) { // 发送失败
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
update.message().chat().id(),
|
|
||||||
String.format("""
|
|
||||||
<b><u>%d</u> FAILED</b>
|
|
||||||
<code>%s</code>""",
|
|
||||||
sendResponse.errorCode(),
|
|
||||||
sendResponse.description()
|
|
||||||
)
|
|
||||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
|
||||||
} else { // 发送成功信号
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
update.message().chat().id(),
|
|
||||||
TelegramStickers.ID_SENT
|
|
||||||
).replyToMessageId(update.message().messageId()));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
// 发送完成/失败 - 事件结束
|
|
||||||
}
|
|
||||||
|
|
||||||
// *msg 检查标识
|
|
||||||
if (update.message().text().equals("*msg")) { // 处理对曾经的原文的检查
|
|
||||||
if (update.message().replyToMessage() == null) {
|
|
||||||
return answer404(update);
|
|
||||||
}
|
|
||||||
msgsendReqRaw = update.message().replyToMessage();
|
|
||||||
} else if (update.message().text().startsWith("*msg")) { // 对接受到的原文进行检查
|
|
||||||
msgsendReqRaw = update.message();
|
|
||||||
} else {
|
|
||||||
return answer404(update); // 未定义的动作
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对发送请求的用户原文进行解析
|
|
||||||
msgsendReqBody = parseRequest(msgsendReqRaw);
|
|
||||||
if (msgsendReqBody == null) {
|
|
||||||
return answer404(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输出发送目标信息
|
|
||||||
GetChatResponse targetChatReq = MornyCoeur.getAccount().execute(new GetChat(msgsendReqBody.targetId()));
|
|
||||||
if (!targetChatReq.isOk()) {
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
update.message().chat().id(),
|
|
||||||
String.format("""
|
|
||||||
<b><u>%d</u> FAILED</b>
|
|
||||||
<code>%s</code>""",
|
|
||||||
targetChatReq.errorCode(),
|
|
||||||
targetChatReq.description()
|
|
||||||
)
|
|
||||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
|
||||||
} else {
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
update.message().chat().id(),
|
|
||||||
targetChatReq.chat().type() == Chat.Type.Private ? (
|
|
||||||
String.format("""
|
|
||||||
<i><u>%d</u>@%s</i>
|
|
||||||
🔒 <b>%s</b> %s""",
|
|
||||||
msgsendReqBody.targetId(),
|
|
||||||
escapeHtml(targetChatReq.chat().type().name()),
|
|
||||||
escapeHtml(targetChatReq.chat().firstName()+(targetChatReq.chat().lastName()==null?"":" "+targetChatReq.chat().lastName())),
|
|
||||||
targetChatReq.chat().username()==null?
|
|
||||||
String.format("<a href='tg://user?id=%d'>@@</a>", targetChatReq.chat().id()):
|
|
||||||
(escapeHtml("@"+targetChatReq.chat().username()))
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
String.format("""
|
|
||||||
<i><u>%d</u>@%s</i>:::
|
|
||||||
%s <b>%s</b>%s""",
|
|
||||||
msgsendReqBody.targetId(),
|
|
||||||
escapeHtml(targetChatReq.chat().type().name()),
|
|
||||||
switch (targetChatReq.chat().type()) {
|
|
||||||
case group -> "💭";
|
|
||||||
case channel -> "📢";
|
|
||||||
case supergroup -> "💬";
|
|
||||||
default -> "⭕️";
|
|
||||||
},
|
|
||||||
escapeHtml(targetChatReq.chat().title()),
|
|
||||||
targetChatReq.chat().username() != null?String.format(
|
|
||||||
" @%s", escapeHtml(targetChatReq.chat().username())
|
|
||||||
):""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
|
||||||
}
|
|
||||||
// 发送文本测试
|
|
||||||
if (msgsendReqBody.message == null) return true;
|
|
||||||
final SendResponse testSendResp = MornyCoeur.getAccount().execute(
|
|
||||||
parseMessageToSend(msgsendReqBody, update.message().chat().id()).replyToMessageId(update.message().messageId())
|
|
||||||
);
|
|
||||||
if (!testSendResp.isOk()) {
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
update.message().chat().id(),
|
|
||||||
String.format("""
|
|
||||||
<b><u>%d</u> FAILED</b>
|
|
||||||
<code>%s</code>""",
|
|
||||||
testSendResp.errorCode(),
|
|
||||||
testSendResp.description()
|
|
||||||
)
|
|
||||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static MessageToSend parseRequest (@Nonnull Message requestBody) {
|
|
||||||
|
|
||||||
final Matcher matcher = REGEX_MSG_SENDREQ_DATA_HEAD.matcher(requestBody.text());
|
|
||||||
if (matcher.matches()) {
|
|
||||||
long targetId = Long.parseLong(matcher.group(1));
|
|
||||||
ParseMode parseMode = matcher.group(2) == null ? null : switch (matcher.group(2)) {
|
|
||||||
case "*markdown", "*md", "*m↓" -> ParseMode.MarkdownV2;
|
|
||||||
case "*md1" -> ParseMode.Markdown;
|
|
||||||
case "*html" -> ParseMode.HTML;
|
|
||||||
default -> null;
|
|
||||||
};
|
|
||||||
final int offset = "*msg".length()+matcher.group(1).length()+(matcher.group(2)==null?0:matcher.group(2).length())+1;
|
|
||||||
final ArrayList<MessageEntity> entities = new ArrayList<>();
|
|
||||||
if (requestBody.entities() != null) for (MessageEntity entity : requestBody.entities()) {
|
|
||||||
final MessageEntity parsed = new MessageEntity(entity.type(), entity.offset() - offset, entity.length());
|
|
||||||
if (entity.url() != null) parsed.url(entity.url());
|
|
||||||
if (entity.user() != null) parsed.user(entity.user());
|
|
||||||
if (entity.language() != null) parsed.language(entity.language());
|
|
||||||
entities.add(parsed);
|
|
||||||
}
|
|
||||||
return new MessageToSend(matcher.group(3), entities.toArray(MessageEntity[]::new), parseMode, targetId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private static SendMessage parseMessageToSend (@Nonnull MessageToSend body) {
|
|
||||||
return parseMessageToSend(body, body.targetId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private static SendMessage parseMessageToSend (@Nonnull MessageToSend body, long targetId) {
|
|
||||||
SendMessage sendingBody = new SendMessage(targetId, body.message);
|
|
||||||
if (body.entities != null) sendingBody.entities(body.entities);
|
|
||||||
if (body.parseMode != null) sendingBody.parseMode(body.parseMode);
|
|
||||||
return sendingBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean answer404 (@Nonnull Update update) {
|
|
||||||
MornyCoeur.extra().exec(new SendSticker(
|
|
||||||
update.message().chat().id(),
|
|
||||||
TelegramStickers.ID_404
|
|
||||||
).replyToMessageId(update.message().messageId()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape;
|
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
|
||||||
import com.pengrad.telegrambot.request.SendMessage;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.Log.logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件劫持与序列化工具.
|
|
||||||
* @since 0.4.2.0
|
|
||||||
*/
|
|
||||||
public class OnEventHackHandle extends EventListener {
|
|
||||||
|
|
||||||
/** 事件劫持请求列表 */
|
|
||||||
private static final Map<String, Hacker> hackers = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 触发事件劫持的限定条件.
|
|
||||||
* @since 0.4.2.0
|
|
||||||
*/
|
|
||||||
public enum HackType {
|
|
||||||
/** 只有相同用户发起的事件才会被触发 */
|
|
||||||
USER,
|
|
||||||
/** 只有相同群组内发生的事件才会触发 */
|
|
||||||
GROUP,
|
|
||||||
/** 任何事件都可以触发 */
|
|
||||||
ANY
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Hacker(long fromChatId, long fromMessageId) {
|
|
||||||
@Override public String toString() {
|
|
||||||
return fromChatId + "/" + fromMessageId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 0.4.2.0
|
|
||||||
*/
|
|
||||||
public static void registerHack(long fromMessageId, long fromUserId, long fromChatId, @Nonnull HackType type) {
|
|
||||||
String rec = null;
|
|
||||||
switch (type) {
|
|
||||||
case USER -> rec = String.format("((%d))", fromUserId);
|
|
||||||
case GROUP -> rec = String.format("{{%d}}", fromChatId);
|
|
||||||
case ANY -> rec = "[[]]";
|
|
||||||
}
|
|
||||||
hackers.put(rec, new Hacker(fromChatId, fromMessageId));
|
|
||||||
logger.debug("add hacker track " + rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean onEventHacked (Update update, long chatId, long fromUser) {
|
|
||||||
logger.debug(String.format("got event signed {{%d}}((%d))", chatId, fromUser));
|
|
||||||
Hacker x;
|
|
||||||
x = hackers.remove(String.format("((%d))", fromUser));
|
|
||||||
if (x == null) x = hackers.remove(String.format("{{%d}}", chatId));
|
|
||||||
if (x == null) x = hackers.remove("[[]]");
|
|
||||||
if (x == null) return false;
|
|
||||||
logger.debug("hacked event by " + x);
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(x.fromChatId, String.format(
|
|
||||||
"<code>%s</code>",
|
|
||||||
MsgEscape.escapeHtml(new GsonBuilder().setPrettyPrinting().create().toJson(update))
|
|
||||||
)).parseMode(ParseMode.HTML).replyToMessageId((int)x.fromMessageId));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.message().chat().id(), update.message().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onEditedMessage (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.editedMessage().chat().id(), update.editedMessage().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onChannelPost (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.channelPost().chat().id(), update.channelPost().chat().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.editedChannelPost().chat().id(), update.editedChannelPost().chat().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onInlineQuery (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.inlineQuery().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onChosenInlineResult (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.chosenInlineResult().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCallbackQuery (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.callbackQuery().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShippingQuery (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.shippingQuery().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreCheckoutQuery (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.preCheckoutQuery().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPoll (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPollAnswer (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, 0, update.pollAnswer().user().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMyChatMemberUpdated (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.myChatMember().chat().id(), update.myChatMember().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onChatMemberUpdated (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.chatMember().chat().id(), update.chatMember().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onChatJoinRequest (@Nonnull Update update) {
|
|
||||||
return onEventHacked(update, update.chatJoinRequest().chat().id(), update.chatJoinRequest().from().id());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ import java.util.GregorianCalendar;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class OnKuohuanhuanNeedSleep extends EventListener {
|
public class OnKuohuanhuanNeedSleep implements EventListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
public boolean onMessage (@Nonnull Update update) {
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
|
||||||
import com.pengrad.telegrambot.model.Message;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
public class OnMedicationNotifyApply extends EventListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
|
||||||
return editedMessageProcess(update.editedChannelPost());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onEditedMessage (@Nonnull Update update) {
|
|
||||||
return editedMessageProcess(update.editedMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean editedMessageProcess (Message edited) {
|
|
||||||
if (edited.chat().id() != MornyCoeur.config().medicationNotifyToChat) return false;
|
|
||||||
MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
import com.pengrad.telegrambot.request.SendMessage;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue;
|
|
||||||
|
|
||||||
public class OnQuestionMarkReply extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一个 unicode 的问号字符列表. 不仅有半角全角问号,也包含了变体问号,和叹号结合的问好以及 uni-emoji 问号。
|
|
||||||
* @since 1.0.0-RC3.2
|
|
||||||
*/
|
|
||||||
public static final Set<Character> QUESTION_MARKS = Set.of('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓');
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
|
||||||
|
|
||||||
if (update.message().text() == null) return false;
|
|
||||||
|
|
||||||
if (!probabilityTrue(8)) return false;
|
|
||||||
for (char c : update.message().text().toCharArray()) {
|
|
||||||
if (!QUESTION_MARKS.contains(c)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MornyCoeur.extra().exec(new SendMessage(
|
|
||||||
update.message().chat().id(), update.message().text()
|
|
||||||
).replyToMessageId(update.message().messageId()));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.bot.event;
|
|||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||||
|
|
||||||
public class OnRandomlyTriggered extends EventListener {
|
@Deprecated
|
||||||
|
public class OnRandomlyTriggered implements EventListener {
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * function CODE_IK0XA1
|
// * function CODE_IK0XA1
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
|
||||||
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import static cc.sukazyo.cono.morny.Log.logger;
|
|
||||||
|
|
||||||
public class OnTelegramCommand extends EventListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage (@Nonnull Update event) {
|
|
||||||
if (event.message().text() == null || !event.message().text().startsWith("/") || event.message().text().startsWith("/ ")) {
|
|
||||||
logger.debug("not command");
|
|
||||||
return false; // 检测到非(命令格式)文本,忽略掉命令处理
|
|
||||||
}
|
|
||||||
final InputCommand command = new InputCommand(event.message().text().substring(1));
|
|
||||||
if (!command.getCommand().matches("^\\w+$")) { logger.debug("not command");return false; }
|
|
||||||
logger.debug("is command");
|
|
||||||
if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) {
|
|
||||||
return true; // 检测到命令并非针对 morny,退出整个事件处理链
|
|
||||||
}
|
|
||||||
return MornyCoeur.commandManager().execute(command, event); // 转交命令管理器执行命令
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import cc.sukazyo.cono.morny.bot.command.ISimpleCommand;
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class OnUniMeowTrigger extends EventListener {
|
|
||||||
|
|
||||||
private static final Map<String, ISimpleCommand> triggers = new HashMap<>();
|
|
||||||
|
|
||||||
public static void register (ISimpleCommand... list) {
|
|
||||||
for (ISimpleCommand cmd : list)
|
|
||||||
triggers.put(cmd.getName(), cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage (@Nonnull Update event) {
|
|
||||||
if (event.message().text() == null) return false;
|
|
||||||
AtomicBoolean ok = new AtomicBoolean(false);
|
|
||||||
triggers.forEach((name, command) -> {
|
|
||||||
name = "/" + name;
|
|
||||||
if (name.equals(event.message().text())) {
|
|
||||||
command.execute(new InputCommand(name), event);
|
|
||||||
ok.set(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ok.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
|
||||||
import com.pengrad.telegrambot.model.Update;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 阻止 {@link cc.sukazyo.cono.morny.MornyConfig#eventOutdatedTimestamp 指定时间} 之前的事件处理.
|
|
||||||
* <p>
|
|
||||||
* 只支持以下事件
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link EventListener#onMessage(Update) 收到消息}</li>
|
|
||||||
* <li>{@link EventListener#onEditedMessage(Update) 消息被更新}</li>
|
|
||||||
* <li>{@link EventListener#onChannelPost(Update) 收到频道消息}</li>
|
|
||||||
* <li>{@link EventListener#onEditedChannelPost(Update) 频道消息被更新}</li>
|
|
||||||
* </ul>
|
|
||||||
* @see #isOutdated 时间判断
|
|
||||||
*/
|
|
||||||
public class OnUpdateTimestampOffsetLock extends EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查传入时间是否在要求时间之前(即"过期").
|
|
||||||
* @param timestamp 传入时间,秒级
|
|
||||||
* @return 如果传入时间在要求时间<u>之前</u>,返回true,反之false
|
|
||||||
* @since 0.4.2.7
|
|
||||||
*/
|
|
||||||
public boolean isOutdated(long timestamp) {
|
|
||||||
return timestamp < MornyCoeur.config().eventOutdatedTimestamp/1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMessage (@Nonnull Update update) {
|
|
||||||
return isOutdated(update.message().date());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 0.4.2.6 */
|
|
||||||
@Override
|
|
||||||
public boolean onEditedMessage (@Nonnull Update update) {
|
|
||||||
return isOutdated(update.editedMessage().editDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 0.4.2.6 */
|
|
||||||
@Override
|
|
||||||
public boolean onChannelPost (@Nonnull Update update) {
|
|
||||||
return isOutdated(update.channelPost().date());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 0.4.2.6 */
|
|
||||||
@Override
|
|
||||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
|
||||||
return isOutdated(update.editedChannelPost().editDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -37,7 +37,7 @@ public class MornyReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exception (@Nonnull Exception e, @Nullable String description) {
|
public static void exception (@Nonnull Throwable e, @Nullable String description) {
|
||||||
if (unsupported()) return;
|
if (unsupported()) return;
|
||||||
executeReport(new SendMessage(
|
executeReport(new SendMessage(
|
||||||
MornyCoeur.config().reportToChat,
|
MornyCoeur.config().reportToChat,
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.data;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.util.CommonConvert;
|
|
||||||
import cc.sukazyo.cono.morny.util.CommonEncrypt;
|
|
||||||
import com.pengrad.telegrambot.model.User;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Morny 的 jrrp 运算类.
|
|
||||||
*
|
|
||||||
* @see #getJrrpFromTelegramUser(User,long)
|
|
||||||
* @see #calcJrrpXmomi(long,long)
|
|
||||||
* @since 0.4.2.9
|
|
||||||
*/
|
|
||||||
public class MornyJrrp {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过 telegram 用户和时间戳作为参数获取 jrrp.
|
|
||||||
*
|
|
||||||
* @see #calcJrrpXmomi 当前版本的实现算法 {@code Xmomi}
|
|
||||||
* @since 0.4.2.9
|
|
||||||
* @param user telegram 用户
|
|
||||||
* @param timestamp 时间戳
|
|
||||||
* @return 通过当前版本的算法计算出的用户 jrrp 值,取值为 {@code [0.00, 100.00]}
|
|
||||||
*/
|
|
||||||
public static double getJrrpFromTelegramUser (User user, long timestamp) {
|
|
||||||
return calcJrrpXmomi(user.id(), timestamp / (1000 * 60 * 60 * 24)) * 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code Xmomi} 版本的 jrrp 算法.
|
|
||||||
* <p>
|
|
||||||
* 算法规则为,将用户id与日期戳链接为 <u><code>uid@daystamp</code></u> 这样的字符串,
|
|
||||||
* 然后通过 MD5 计算出字符串的哈希值,取哈希值前4个字节,将其作为16进制数值表示法转换为取值为 {@code [0x0000, 0xffff]} 的数值,
|
|
||||||
* 得到的数值除以区间最大值 {@code 0xffff} 即可得到一个分布在 {@code [0.0, 1.0]} 之间的分布值,
|
|
||||||
* 这个分布值乘以 {@code 100.0},即为计算得到的 jrrp 数值。
|
|
||||||
*
|
|
||||||
* @since 0.4.2.9
|
|
||||||
* @param userId telegram 用户 uid
|
|
||||||
* @param dayStamp unix 时间戳转换为日期单位后的数值. 数值应该在转换前转换时区
|
|
||||||
* @return 算法得到的 jrrp 值,取值为 {@code [0.00. 100.00]}
|
|
||||||
*/
|
|
||||||
public static double calcJrrpXmomi (long userId, long dayStamp) {
|
|
||||||
return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package cc.sukazyo.cono.morny.data;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.RequestBody;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
|
|
||||||
public class NbnhhshQuery {
|
|
||||||
|
|
||||||
public static class Word {
|
|
||||||
public String name;
|
|
||||||
public String[] trans;
|
|
||||||
public String[] inputting;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GuessResult {
|
|
||||||
public Word[] words;
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GuessReq (String text) {}
|
|
||||||
|
|
||||||
public static final String API_URL = "https://lab.magiconch.com/api/nbnhhsh/";
|
|
||||||
public static final String API_GUESS_METHOD = "guess/";
|
|
||||||
|
|
||||||
private static final OkHttpClient httpClient = new OkHttpClient();
|
|
||||||
|
|
||||||
public static GuessResult sendGuess (String text) throws IOException {
|
|
||||||
final String reqJsonText = new Gson().toJson(new GuessReq(text));
|
|
||||||
Request request = new Request.Builder()
|
|
||||||
.url(API_URL + API_GUESS_METHOD)
|
|
||||||
.post(RequestBody.create(reqJsonText, MediaTypes.JSON))
|
|
||||||
.build();
|
|
||||||
try (Response response = httpClient.newCall(request).execute()) {
|
|
||||||
final ResponseBody body = response.body();
|
|
||||||
if (body == null) throw new IOException("Null body.");
|
|
||||||
final String x = "{ \"words\": " + body.string() + " }";
|
|
||||||
return new Gson().fromJson(x, GuessResult.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,10 +1,15 @@
|
|||||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||||
|
|
||||||
import com.pengrad.telegrambot.model.Chat;
|
import com.pengrad.telegrambot.model.Chat;
|
||||||
import com.pengrad.telegrambot.model.Message;
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class TGToStringFromChat {
|
public class TGToStringFromChat {
|
||||||
|
|
||||||
|
|
||||||
|
public static final long MASK_BOTAPI_ID = -1000000000000L;
|
||||||
|
|
||||||
private final Chat data;
|
private final Chat data;
|
||||||
|
|
||||||
public TGToStringFromChat(Chat chat) {
|
public TGToStringFromChat(Chat chat) {
|
||||||
@ -20,4 +25,36 @@ public class TGToStringFromChat {
|
|||||||
(String.format("%s {%s}[%d]", data.title(), data.username(), data.id()));
|
(String.format("%s {%s}[%d]", data.title(), data.username(), data.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public String getSafeName () {
|
||||||
|
if (data.type() == Chat.Type.Private)
|
||||||
|
return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName());
|
||||||
|
else return data.title();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getSafeLinkHTML () {
|
||||||
|
if (data.username() == null) {
|
||||||
|
if (data.type() == Chat.Type.Private)
|
||||||
|
// language=html
|
||||||
|
return String.format("<a href='tg://user?id=%d'>@[u:%d]</a>", data.id(), data.id());
|
||||||
|
// language=html
|
||||||
|
else return String.format("<a href='https://t.me/c/%d'>@[c/%d]</a>", id_tdLib(), id_tdLib());
|
||||||
|
} else return "@"+data.username();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long id_tdLib () {
|
||||||
|
return data.id() < 0 ? Math.abs(data.id() - MASK_BOTAPI_ID) : data.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public String getTypeTag () {
|
||||||
|
return switch (data.type()) {
|
||||||
|
case Private -> "🔒";
|
||||||
|
case group -> "💭";
|
||||||
|
case supergroup -> "💬";
|
||||||
|
case channel -> "📢";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.api
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
trait EventListener {
|
||||||
|
|
||||||
|
def onMessage (using Update): Boolean = false
|
||||||
|
def onEditedMessage (using Update): Boolean = false
|
||||||
|
def onChannelPost (using Update): Boolean = false
|
||||||
|
def onEditedChannelPost (using Update): Boolean = false
|
||||||
|
def onInlineQuery (using Update): Boolean = false
|
||||||
|
def onChosenInlineResult (using Update): Boolean = false
|
||||||
|
def onCallbackQuery (using Update): Boolean = false
|
||||||
|
def onShippingQuery (using Update): Boolean = false
|
||||||
|
def onPreCheckoutQuery (using Update): Boolean = false
|
||||||
|
def onPoll (using Update): Boolean = false
|
||||||
|
def onPollAnswer (using Update): Boolean = false
|
||||||
|
def onMyChatMemberUpdated (using Update): Boolean = false
|
||||||
|
def onChatMemberUpdated (using Update): Boolean = false
|
||||||
|
def onChatJoinRequest (using Update): Boolean = false
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.api
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.Log
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException
|
||||||
|
import cc.sukazyo.cono.morny.Log.{exceptionLog, logger}
|
||||||
|
import cc.sukazyo.cono.morny.daemon.MornyReport
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
object EventListenerManager {
|
||||||
|
|
||||||
|
private val listeners = mutable.Queue.empty[EventListener]
|
||||||
|
|
||||||
|
def register (listeners: EventListener*): Unit =
|
||||||
|
this.listeners ++= listeners
|
||||||
|
|
||||||
|
private class EventRunner (using event: Update) extends Thread {
|
||||||
|
this setName s"evt-${event.updateId()}-nn"
|
||||||
|
private def updateThreadName (t: String): Unit =
|
||||||
|
this setName s"evt-${event.updateId()}-$t"
|
||||||
|
|
||||||
|
override def run (): Unit = {
|
||||||
|
for (i <- listeners) {
|
||||||
|
object status:
|
||||||
|
var _status = 0
|
||||||
|
def isOk: Boolean = _status > 0
|
||||||
|
def check (u: Boolean): Unit = if u then _status = _status + 1
|
||||||
|
try {
|
||||||
|
updateThreadName("message")
|
||||||
|
if event.message ne null then status check i.onMessage
|
||||||
|
updateThreadName("edited-message")
|
||||||
|
if event.editedMessage ne null then status check i.onEditedMessage
|
||||||
|
updateThreadName("channel-post")
|
||||||
|
if event.channelPost ne null then status check i.onChannelPost
|
||||||
|
updateThreadName("edited-channel-post")
|
||||||
|
if event.editedChannelPost ne null then status check i.onEditedChannelPost
|
||||||
|
updateThreadName("inline-query")
|
||||||
|
if event.inlineQuery ne null then status check i.onInlineQuery
|
||||||
|
updateThreadName("chosen-inline-result")
|
||||||
|
if event.chosenInlineResult ne null then status check i.onChosenInlineResult
|
||||||
|
updateThreadName("callback-query")
|
||||||
|
if event.callbackQuery ne null then status check i.onCallbackQuery
|
||||||
|
updateThreadName("shipping-query")
|
||||||
|
if event.shippingQuery ne null then status check i.onShippingQuery
|
||||||
|
updateThreadName("pre-checkout-query")
|
||||||
|
if event.preCheckoutQuery ne null then status check i.onPreCheckoutQuery
|
||||||
|
updateThreadName("poll")
|
||||||
|
if event.poll ne null then status check i.onPoll
|
||||||
|
updateThreadName("poll-answer")
|
||||||
|
if event.pollAnswer ne null then status check i.onPollAnswer
|
||||||
|
updateThreadName("my-chat-member")
|
||||||
|
if event.myChatMember ne null then status check i.onMyChatMemberUpdated
|
||||||
|
updateThreadName("chat-member")
|
||||||
|
if event.chatMember ne null then status check i.onChatMemberUpdated
|
||||||
|
updateThreadName("chat-join-request")
|
||||||
|
if event.chatJoinRequest ne null then status check i.onChatJoinRequest
|
||||||
|
} catch case e => {
|
||||||
|
val errorMessage = StringBuilder()
|
||||||
|
errorMessage ++= "Event throws unexpected exception:\n"
|
||||||
|
errorMessage ++= (exceptionLog(e) indent 4)
|
||||||
|
e match
|
||||||
|
case actionFailed: EventRuntimeException.ActionFailed =>
|
||||||
|
errorMessage ++= "\ntg-api action: response track: "
|
||||||
|
errorMessage ++= (GsonBuilder().setPrettyPrinting().create().toJson(
|
||||||
|
actionFailed.getResponse
|
||||||
|
) indent 4) ++= "\n"
|
||||||
|
case _ =>
|
||||||
|
logger error errorMessage.toString
|
||||||
|
MornyReport.exception(e, "on event running")
|
||||||
|
}
|
||||||
|
if (status isOk) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def publishUpdate (using Update): Unit = {
|
||||||
|
EventRunner().start()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.api
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.UpdatesListener
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
import java.util
|
||||||
|
import scala.jdk.CollectionConverters.*
|
||||||
|
|
||||||
|
object TelegramUpdatesListener extends UpdatesListener {
|
||||||
|
|
||||||
|
override def process (updates: util.List[Update]): Int = {
|
||||||
|
for (update <- updates.asScala)
|
||||||
|
EventListenerManager.publishUpdate(using update)
|
||||||
|
UpdatesListener.CONFIRMED_UPDATES_ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,10 +11,10 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object DirectMsgClear extends ISimpleCommand {
|
object DirectMsgClear extends ISimpleCommand {
|
||||||
|
|
||||||
override def getName: String = "r"
|
override val name: String = "r"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
logger debug "executing command /r"
|
logger debug "executing command /r"
|
||||||
if (event.message.replyToMessage == null) return;
|
if (event.message.replyToMessage == null) return;
|
||||||
|
@ -18,12 +18,12 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object Encryptor extends ITelegramCommand {
|
object Encryptor extends ITelegramCommand {
|
||||||
|
|
||||||
override def getName: String = "encrypt"
|
override val name: String = "encrypt"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
override def getParamRule: String = "[algorithm|(l)] [(uppercase)]"
|
override val paramRule: String = "[algorithm|(l)] [(uppercase)]"
|
||||||
override def getDescription: String = "通过指定算法加密回复的内容 (目前只支持文本)"
|
override val description: String = "通过指定算法加密回复的内容 (目前只支持文本)"
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val args = command.getArgs
|
val args = command.getArgs
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object EventHack extends ITelegramCommand {
|
object EventHack extends ITelegramCommand {
|
||||||
|
|
||||||
override def getName: String = "event_hack"
|
override val name: String = "event_hack"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
override def getParamRule: String = "[(user|group|any)]"
|
override val paramRule: String = "[(user|group|any)]"
|
||||||
override def getDescription: String = "输出 bot 下一个获取到的事件序列化数据"
|
override val description: String = "输出 bot 下一个获取到的事件序列化数据"
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val x_mode = if (command.hasArgs) command.getArgs()(0) else ""
|
val x_mode = if (command.hasArgs) command.getArgs()(0) else ""
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.{InputCommand, Standardize}
|
import cc.sukazyo.cono.morny.util.tgapi.{InputCommand, Standardize}
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode
|
import com.pengrad.telegrambot.model.request.ParseMode
|
||||||
import com.pengrad.telegrambot.request.{GetChatMember, SendMessage}
|
import com.pengrad.telegrambot.request.{GetChatMember, SendMessage}
|
||||||
@ -10,12 +11,12 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object GetUsernameAndId extends ITelegramCommand {
|
object GetUsernameAndId extends ITelegramCommand {
|
||||||
|
|
||||||
override def getName: String = "user"
|
override val name: String = "user"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
override def getParamRule: String = "[userid]"
|
override val paramRule: String = "[userid]"
|
||||||
override def getDescription: String = "获取指定或回复的用户相关信息"
|
override val description: String = "获取指定或回复的用户相关信息"
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val args = command.getArgs
|
val args = command.getArgs
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ object GetUsernameAndId extends ITelegramCommand {
|
|||||||
|
|
||||||
val user = response.chatMember.user
|
val user = response.chatMember.user
|
||||||
|
|
||||||
if (user.id eq Standardize.CHANNEL_SPEAKER_MAGIC_ID)
|
if (user.id == Standardize.CHANNEL_SPEAKER_MAGIC_ID)
|
||||||
MornyCoeur.extra exec SendMessage(
|
MornyCoeur.extra exec SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
"<code>$__channel_identify</code>"
|
"<code>$__channel_identify</code>"
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
trait ICommandAlias {
|
||||||
|
|
||||||
|
val name: String
|
||||||
|
val listed: Boolean
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object ICommandAlias {
|
||||||
|
|
||||||
|
case class ListedAlias (name: String) extends ICommandAlias:
|
||||||
|
override val listed = true
|
||||||
|
|
||||||
|
case class HiddenAlias (name: String) extends ICommandAlias:
|
||||||
|
override val listed = false
|
||||||
|
|
||||||
|
}
|
@ -16,19 +16,19 @@ object IP186Query {
|
|||||||
case WHOIS extends Subs("whois")
|
case WHOIS extends Subs("whois")
|
||||||
|
|
||||||
object IP extends ITelegramCommand:
|
object IP extends ITelegramCommand:
|
||||||
override def getName: String = "ip"
|
override val name: String = "ip"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def getParamRule: String = "[ip]"
|
override val paramRule: String = "[ip]"
|
||||||
override def getDescription: String = "通过 https://ip.186526.xyz 查询 ip 资料"
|
override val description: String = "通过 https://ip.186526.xyz 查询 ip 资料"
|
||||||
override def execute (command: InputCommand, event: Update): Unit = query(event, command)
|
override def execute (using command: InputCommand, event: Update): Unit = query
|
||||||
object Whois extends ITelegramCommand:
|
object Whois extends ITelegramCommand:
|
||||||
override def getName: String = "whois"
|
override val name: String = "whois"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def getParamRule: String = "[domain]"
|
override val paramRule: String = "[domain]"
|
||||||
override def getDescription: String = "通过 https://ip.186526.xyz 查询域名资料"
|
override val description: String = "通过 https://ip.186526.xyz 查询域名资料"
|
||||||
override def execute (command: InputCommand, event: Update): Unit = query(event, command)
|
override def execute (using command: InputCommand, event: Update): Unit = query
|
||||||
|
|
||||||
private def query (event: Update, command: InputCommand): Unit = {
|
private def query (using event: Update, command: InputCommand): Unit = {
|
||||||
|
|
||||||
val target: String|Null =
|
val target: String|Null =
|
||||||
if (command.getArgs isEmpty)
|
if (command.getArgs isEmpty)
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
trait ISimpleCommand {
|
||||||
|
|
||||||
|
val name: String
|
||||||
|
val aliases: Array[ICommandAlias]|Null
|
||||||
|
|
||||||
|
def execute (using command: InputCommand, event: Update): Unit
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
trait ITelegramCommand extends ISimpleCommand {
|
||||||
|
|
||||||
|
val paramRule: String
|
||||||
|
val description: String
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
|
import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update}
|
||||||
|
import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands}
|
||||||
|
|
||||||
|
import scala.collection.{mutable, SeqMap}
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import scala.language.postfixOps
|
||||||
|
import cc.sukazyo.cono.morny.Log.logger
|
||||||
|
|
||||||
|
object MornyCommands {
|
||||||
|
|
||||||
|
private type CommandMap = SeqMap[String, ISimpleCommand]
|
||||||
|
private def CommandMap (commands: ISimpleCommand*): CommandMap =
|
||||||
|
val stash: mutable.SeqMap[String, ISimpleCommand] = mutable.SeqMap()
|
||||||
|
for (i <- commands) stash += ((i.name, i))
|
||||||
|
stash
|
||||||
|
|
||||||
|
private val commands: CommandMap = CommandMap(
|
||||||
|
|
||||||
|
MornyHellos.On,
|
||||||
|
MornyHellos.On,
|
||||||
|
MornyHellos.Hello,
|
||||||
|
MornyInfoOnStart,
|
||||||
|
GetUsernameAndId,
|
||||||
|
EventHack,
|
||||||
|
Nbnhhsh,
|
||||||
|
IP186Query.IP,
|
||||||
|
IP186Query.Whois,
|
||||||
|
Encryptor,
|
||||||
|
MornyManagers.SaveData,
|
||||||
|
MornyInformation,
|
||||||
|
MornyInformationOlds.Version,
|
||||||
|
MornyInformationOlds.Runtime,
|
||||||
|
MornyOldJrrp,
|
||||||
|
MornyManagers.Exit,
|
||||||
|
|
||||||
|
Testing,
|
||||||
|
DirectMsgClear,
|
||||||
|
|
||||||
|
私わね,
|
||||||
|
喵呜.Progynova
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
@SuppressWarnings(Array("NonAsciiCharacters"))
|
||||||
|
val commands_uni: CommandMap = CommandMap(
|
||||||
|
喵呜.抱抱,
|
||||||
|
喵呜.揉揉,
|
||||||
|
喵呜.贴贴,
|
||||||
|
喵呜.蹭蹭
|
||||||
|
)
|
||||||
|
|
||||||
|
def execute (using command: InputCommand, event: Update): Boolean = {
|
||||||
|
if (commands contains command.getCommand)
|
||||||
|
commands(command.getCommand) execute;
|
||||||
|
true
|
||||||
|
else nonCommandExecutable
|
||||||
|
}
|
||||||
|
|
||||||
|
private def nonCommandExecutable (using command: InputCommand, event: Update): Boolean = {
|
||||||
|
if command.getTarget eq null then false
|
||||||
|
else
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_404
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
def automaticTGListUpdate (): Unit = {
|
||||||
|
val listing = commands_toTelegramList
|
||||||
|
automaticTGListRemove()
|
||||||
|
MornyCoeur.extra exec SetMyCommands(listing:_*)
|
||||||
|
logger info
|
||||||
|
s"""automatic updated telegram command list :
|
||||||
|
|${commandsTelegramList_toString(listing)}""".stripMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
def automaticTGListRemove (): Unit = {
|
||||||
|
MornyCoeur.extra exec DeleteMyCommands()
|
||||||
|
logger info "cleaned up command list"
|
||||||
|
}
|
||||||
|
|
||||||
|
private def commandsTelegramList_toString (list: Array[BotCommand]): String =
|
||||||
|
val builder = StringBuilder()
|
||||||
|
for (single <- list)
|
||||||
|
builder ++= s"${single.command} - ${single.description}\n"
|
||||||
|
(builder dropRight 1) toString
|
||||||
|
|
||||||
|
private def commands_toTelegramList: Array[BotCommand] =
|
||||||
|
val list = ArrayBuffer.empty[BotCommand]
|
||||||
|
for ((name, command) <- commands) command match
|
||||||
|
case telegramCommand: ITelegramCommand if name == command.name =>
|
||||||
|
list ++= formatTelegramCommandListLine(telegramCommand)
|
||||||
|
case _ =>
|
||||||
|
list toArray
|
||||||
|
|
||||||
|
private def formatTelegramCommandListLine (command: ITelegramCommand): Array[BotCommand] =
|
||||||
|
def buildOne (name: String, paramRule: String, intro: String): BotCommand =
|
||||||
|
BotCommand(name, if paramRule isBlank then intro else s"$paramRule - $intro")
|
||||||
|
val list = mutable.ArrayBuffer[BotCommand](
|
||||||
|
buildOne(command.name, command.paramRule, command.description))
|
||||||
|
if (command.aliases ne null) for (alias <- command.aliases)
|
||||||
|
if (alias.listed) list += buildOne(alias.name, "", "↑")
|
||||||
|
list toArray
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias
|
||||||
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
import com.pengrad.telegrambot.request.SendSticker
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
object MornyHellos {
|
||||||
|
|
||||||
|
object On extends ITelegramCommand {
|
||||||
|
|
||||||
|
override val name: String = "on"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
override val paramRule: String = ""
|
||||||
|
override val description: String = "检查是否在线"
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_ONLINE_STATUS_RETURN
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Hello extends ITelegramCommand {
|
||||||
|
|
||||||
|
override val name: String = "hello"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = Array(ListedAlias("hi"))
|
||||||
|
override val paramRule: String = ""
|
||||||
|
override val description: String = "打招呼"
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_HELLO
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,12 +8,12 @@ import com.pengrad.telegrambot.request.SendPhoto
|
|||||||
|
|
||||||
import scala.language.postfixOps
|
import scala.language.postfixOps
|
||||||
|
|
||||||
object MornyInfoOnHello extends ISimpleCommand {
|
object MornyInfoOnStart extends ISimpleCommand {
|
||||||
|
|
||||||
override def getName: String = "start"
|
override val name: String = "start"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
MornyCoeur.extra exec new SendPhoto(
|
MornyCoeur.extra exec new SendPhoto(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
@ -23,12 +23,12 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
val VERSION_2 = "v"
|
val VERSION_2 = "v"
|
||||||
}
|
}
|
||||||
|
|
||||||
override def getName: String = "info"
|
override val name: String = "info"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def getParamRule: String = "[(version|runtime|stickers[.IDs])]"
|
override val paramRule: String = "[(version|runtime|stickers[.IDs])]"
|
||||||
override def getDescription: String = "输出当前 Morny 的各种信息"
|
override val description: String = "输出当前 Morny 的各种信息"
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
if (!command.hasArgs) {
|
if (!command.hasArgs) {
|
||||||
echoInfo(event.message.chat.id, event.message.messageId)
|
echoInfo(event.message.chat.id, event.message.messageId)
|
||||||
@ -38,10 +38,10 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
val action: String = command.getArgs()(0)
|
val action: String = command.getArgs()(0)
|
||||||
|
|
||||||
action match {
|
action match {
|
||||||
case Subs.STICKERS => echoStickers(command, event)
|
case Subs.STICKERS => echoStickers
|
||||||
case Subs.RUNTIME => echoRuntime(event)
|
case Subs.RUNTIME => echoRuntime
|
||||||
case Subs.VERSION | Subs.VERSION_2 => echoVersion(event)
|
case Subs.VERSION | Subs.VERSION_2 => echoVersion
|
||||||
case _ => echo404(event)
|
case _ => echo404
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -92,11 +92,11 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
).parseMode(ParseMode HTML).replyToMessageId(replyTo)
|
).parseMode(ParseMode HTML).replyToMessageId(replyTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def echoStickers (command: InputCommand, event: Update): Unit = {
|
private def echoStickers (using command: InputCommand, event: Update): Unit = {
|
||||||
val chat = event.message.chat.id
|
val chat = event.message.chat.id
|
||||||
val replyTo = event.message.messageId
|
val replyTo = event.message.messageId
|
||||||
var sid: String|Null = null
|
var sid: String|Null = null
|
||||||
if (command.getArgs()(0) eq Subs.STICKERS) {
|
if (command.getArgs()(0) == Subs.STICKERS) {
|
||||||
if (command.getArgs.length == 1) sid = ""
|
if (command.getArgs.length == 1) sid = ""
|
||||||
else if (command.getArgs.length == 2) sid = command.getArgs()(1)
|
else if (command.getArgs.length == 2) sid = command.getArgs()(1)
|
||||||
} else if (command.getArgs.length == 1) {
|
} else if (command.getArgs.length == 1) {
|
||||||
@ -104,7 +104,7 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
sid = command.getArgs()(0) substring Subs.STICKERS.length+1
|
sid = command.getArgs()(0) substring Subs.STICKERS.length+1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sid == null) echo404(event)
|
if (sid == null) echo404
|
||||||
else echoStickers(sid, chat, replyTo)
|
else echoStickers(sid, chat, replyTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,11 +113,12 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo)
|
else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[command] def echoVersion (event: Update): Unit = {
|
private[command] def echoVersion (using event: Update): Unit = {
|
||||||
val versionDeltaHTML = if (MornySystem.isUseDelta) s"-δ<code>${h(MornySystem.VERSION_DELTA)}</code>" else ""
|
val versionDeltaHTML = if (MornySystem.isUseDelta) s"-δ<code>${h(MornySystem.VERSION_DELTA)}</code>" else ""
|
||||||
val versionGitHTML = if (MornySystem.isGitBuild) s"git $getVersionGitTagHTML" else ""
|
val versionGitHTML = if (MornySystem.isGitBuild) s"git $getVersionGitTagHTML" else ""
|
||||||
MornyCoeur.extra exec new SendMessage(
|
MornyCoeur.extra exec new SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
|
// language=html
|
||||||
s"""version:
|
s"""version:
|
||||||
|- Morny <code>${h(MornySystem.CODENAME toUpperCase)}</code>
|
|- Morny <code>${h(MornySystem.CODENAME toUpperCase)}</code>
|
||||||
|- <code>${h(MornySystem.VERSION_BASE)}</code>$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""}
|
|- <code>${h(MornySystem.VERSION_BASE)}</code>$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""}
|
||||||
@ -130,11 +131,11 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[command] def echoRuntime (event: Update): Unit = {
|
private[command] def echoRuntime (using event: Update): Unit = {
|
||||||
def sysprop (p: String): String = System.getProperty(p)
|
def sysprop (p: String): String = System.getProperty(p)
|
||||||
MornyCoeur.extra exec new SendMessage(
|
MornyCoeur.extra exec new SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
/* html */
|
/* language=html */
|
||||||
s"""system:
|
s"""system:
|
||||||
|- Morny <code>${h(if (getRuntimeHostname == null) "<unknown-host>" else getRuntimeHostname)}</code>
|
|- Morny <code>${h(if (getRuntimeHostname == null) "<unknown-host>" else getRuntimeHostname)}</code>
|
||||||
|- <code>${h(sysprop("os.name"))}</code> <code>${h(sysprop("os.arch"))}</code> <code>${h(sysprop("os.version"))}</code>
|
|- <code>${h(sysprop("os.name"))}</code> <code>${h(sysprop("os.arch"))}</code> <code>${h(sysprop("os.version"))}</code>
|
||||||
@ -158,7 +159,7 @@ object MornyInformation extends ITelegramCommand {
|
|||||||
).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId)
|
).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def echo404 (event: Update): Unit =
|
private def echo404 (using event: Update): Unit =
|
||||||
MornyCoeur.extra exec new SendSticker(
|
MornyCoeur.extra exec new SendSticker(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
TelegramStickers ID_404
|
TelegramStickers ID_404
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
object MornyInformationOlds {
|
||||||
|
|
||||||
|
object Version extends ISimpleCommand:
|
||||||
|
override val name: String = "version"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoVersion
|
||||||
|
|
||||||
|
object Runtime extends ISimpleCommand:
|
||||||
|
override val name: String = "runtime"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoRuntime
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
import com.pengrad.telegrambot.request.SendSticker
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
import cc.sukazyo.cono.morny.Log.logger
|
||||||
|
import cc.sukazyo.cono.morny.daemon.MornyReport
|
||||||
|
|
||||||
|
object MornyManagers {
|
||||||
|
|
||||||
|
object Exit extends ITelegramCommand {
|
||||||
|
|
||||||
|
override val name: String = "exit"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = Array(HiddenAlias("stop"), HiddenAlias("quit"))
|
||||||
|
override val paramRule: String = "exit"
|
||||||
|
override val description: String = "关闭 Bot (仅可信成员)"
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
|
val user = event.message.from
|
||||||
|
|
||||||
|
if (MornyCoeur.trustedInstance isTrusted user.id) {
|
||||||
|
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_EXIT
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
logger info s"Morny exited by user ${(TGToString as user) toStringLogTag}"
|
||||||
|
MornyCoeur.exit(0, user)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_403
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
logger info s"403 exit caught from user ${(TGToString as user) toStringLogTag}"
|
||||||
|
MornyReport.unauthenticatedAction("/exit", user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object SaveData extends ITelegramCommand {
|
||||||
|
|
||||||
|
override val name: String = "save"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
override val paramRule: String = ""
|
||||||
|
override val description: String = "保存缓存数据到文件(仅可信成员)"
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
|
val user = event.message.from
|
||||||
|
|
||||||
|
if (MornyCoeur.trustedInstance isTrusted user.id) {
|
||||||
|
|
||||||
|
logger info s"call save from command by ${(TGToString as user) toStringLogTag}"
|
||||||
|
MornyCoeur.callSaveData()
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_SAVED
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
event.message.chat.id,
|
||||||
|
TelegramStickers ID_403
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
logger info s"403 save caught from user ${(TGToString as user) toStringLogTag}"
|
||||||
|
MornyReport.unauthenticatedAction("/save", user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
import cc.sukazyo.cono.morny.data.MornyJrrp
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||||
|
import com.pengrad.telegrambot.model.request.ParseMode
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
object MornyOldJrrp extends ITelegramCommand {
|
||||||
|
|
||||||
|
override val name: String = "jrrp"
|
||||||
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
override val paramRule: String = ""
|
||||||
|
override val description: String = "获取 (假的) jrrp"
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
|
val user = event.message.from
|
||||||
|
val jrrp = MornyJrrp.jrrp_of_telegramUser(user, System.currentTimeMillis)
|
||||||
|
val ending = jrrp match
|
||||||
|
case s if s > 70 => "!"
|
||||||
|
case a if a > 30 => ";"
|
||||||
|
case _ => "..."
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
event.message.chat.id,
|
||||||
|
// language=html
|
||||||
|
f"${(TGToString as user) fullnameRefHtml} 在(utc的)今天的运气指数是———— <code>$jrrp%.2f%%</code>${h(ending)}"
|
||||||
|
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,14 +13,16 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object Nbnhhsh extends ITelegramCommand {
|
object Nbnhhsh extends ITelegramCommand {
|
||||||
|
|
||||||
private val NBNHHSH_RESULT_HEAD_HTML = "<a href=\"https://lab.magiconch.com/nbnhhsh/\">## Result of nbnhhsh query :</a>"
|
private val NBNHHSH_RESULT_HEAD_HTML =
|
||||||
|
// language=html
|
||||||
|
"<a href=\"https://lab.magiconch.com/nbnhhsh/\">## Result of nbnhhsh query :</a>"
|
||||||
|
|
||||||
override def getName: String = "nbnhhsh"
|
override val name: String = "nbnhhsh"
|
||||||
override def getAliases: Array[String]|Null = null
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def getParamRule: String = "[text]"
|
override val paramRule: String = "[text]"
|
||||||
override def getDescription: String = "检索文本内 nbnhhsh 词条"
|
override val description: String = "检索文本内 nbnhhsh 词条"
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val queryTarget: String|Null =
|
val queryTarget: String|Null =
|
||||||
import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting
|
import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting
|
||||||
@ -47,17 +49,17 @@ object Nbnhhsh extends ITelegramCommand {
|
|||||||
logger debug s"**xx len=${queryResp.words.length}"
|
logger debug s"**xx len=${queryResp.words.length}"
|
||||||
for (_word <- queryResp.words) {
|
for (_word <- queryResp.words) {
|
||||||
logger debug "**exec"
|
logger debug "**exec"
|
||||||
if ((_word.trans ne null) && (_word.trans isEmpty)) _word.trans = null
|
val _use_trans = (_word.trans ne null) && (_word.trans nonEmpty)
|
||||||
if ((_word.inputting ne null) && (_word.inputting isEmpty)) _word.inputting = null
|
val _use_inputting = (_word.inputting ne null) && (_word.inputting nonEmpty)
|
||||||
if ((_word.trans ne null) || (_word.inputting ne null))
|
if (_use_trans || _use_inputting)
|
||||||
message ++= s"\n\n<b>[[ ${h(_word.name)} ]]</b>"
|
message ++= s"\n\n<b>[[ ${h(_word.name)} ]]</b>"
|
||||||
logger debug s"**used [${_word.name}]"
|
logger debug s"**used [${_word.name}]"
|
||||||
if (_word.trans != null) for (_trans <- _word.trans)
|
if (_use_trans) for (_trans <- _word.trans)
|
||||||
message ++= s"\n* <i>${h(_trans)}</i>"
|
message ++= s"\n* <i>${h(_trans)}</i>"
|
||||||
logger debug s"**used [${_word.name}] used `${_trans}``"
|
logger debug s"**used [${_word.name}] used `${_trans}``"
|
||||||
if (_word.inputting != null)
|
if (_use_inputting)
|
||||||
logger debug s"**used [${_word.name}] inputting"
|
logger debug s"**used [${_word.name}] inputting"
|
||||||
if (_word.trans != null)
|
if (_use_trans)
|
||||||
message += '\n'
|
message += '\n'
|
||||||
message ++= " maybe:"
|
message ++= " maybe:"
|
||||||
for (_inputting <- _word.inputting)
|
for (_inputting <- _word.inputting)
|
||||||
|
@ -12,17 +12,15 @@ import scala.language.postfixOps
|
|||||||
|
|
||||||
object Testing extends ISimpleCommand {
|
object Testing extends ISimpleCommand {
|
||||||
|
|
||||||
override def getName: String = "test"
|
override val name: String = "test"
|
||||||
override def getAliases: Array[String] = null
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val a = StringBuilder("value")
|
|
||||||
a ++= "Changed"
|
|
||||||
|
|
||||||
MornyCoeur.extra exec new SendMessage(
|
MornyCoeur.extra exec new SendMessage(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
"<b>Just</b> a TEST command. num is:" + (a toString)
|
// language=html
|
||||||
|
"<b>Just</b> a TEST command."
|
||||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,39 +15,39 @@ import scala.language.postfixOps
|
|||||||
object 喵呜 {
|
object 喵呜 {
|
||||||
|
|
||||||
object 抱抱 extends ISimpleCommand {
|
object 抱抱 extends ISimpleCommand {
|
||||||
override def getName: String = "抱抱"
|
override val name: String = "抱抱"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def execute (command: InputCommand, event: Update): Unit =
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
replyingSet(event, "贴贴", "贴贴")
|
replyingSet("贴贴", "贴贴")
|
||||||
}
|
}
|
||||||
|
|
||||||
object 揉揉 extends ISimpleCommand {
|
object 揉揉 extends ISimpleCommand {
|
||||||
override def getName: String = "揉揉"
|
override val name: String = "揉揉"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def execute (command: InputCommand, event: Update): Unit =
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
replyingSet(event, "蹭蹭", "摸摸")
|
replyingSet("蹭蹭", "摸摸")
|
||||||
}
|
}
|
||||||
|
|
||||||
object 蹭蹭 extends ISimpleCommand {
|
object 蹭蹭 extends ISimpleCommand {
|
||||||
override def getName: String = "蹭蹭"
|
override val name: String = "蹭蹭"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def execute (command: InputCommand, event: Update): Unit =
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
replyingSet(event, "揉揉", "蹭蹭")
|
replyingSet("揉揉", "蹭蹭")
|
||||||
}
|
}
|
||||||
|
|
||||||
object 贴贴 extends ISimpleCommand {
|
object 贴贴 extends ISimpleCommand {
|
||||||
override def getName: String = "贴贴"
|
override val name: String = "贴贴"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def execute (command: InputCommand, event: Update): Unit =
|
override def execute (using command: InputCommand, event: Update): Unit =
|
||||||
replyingSet(event, "贴贴", "贴贴")
|
replyingSet("贴贴", "贴贴")
|
||||||
}
|
}
|
||||||
|
|
||||||
object Progynova extends ITelegramCommand {
|
object Progynova extends ITelegramCommand {
|
||||||
override def getName: String = "install"
|
override val name: String = "install"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias]|Null = null
|
||||||
override def getParamRule: String = ""
|
override val paramRule: String = ""
|
||||||
override def getDescription: String = "抽取一个神秘盒子"
|
override val description: String = "抽取一个神秘盒子"
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
MornyCoeur.extra exec new SendSticker(
|
MornyCoeur.extra exec new SendSticker(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
TelegramStickers ID_PROGYNOVA
|
TelegramStickers ID_PROGYNOVA
|
||||||
@ -55,7 +55,7 @@ object 喵呜 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def replyingSet (event: Update, whileRec: String, whileNew: String): Unit = {
|
private def replyingSet (whileRec: String, whileNew: String)(using event: Update): Unit = {
|
||||||
val isNew = event.message.replyToMessage == null;
|
val isNew = event.message.replyToMessage == null;
|
||||||
val target = if (isNew) event.message else event.message.replyToMessage
|
val target = if (isNew) event.message else event.message.replyToMessage
|
||||||
MornyCoeur.extra exec new SendMessage(
|
MornyCoeur.extra exec new SendMessage(
|
||||||
|
@ -8,10 +8,10 @@ import com.pengrad.telegrambot.request.SendMessage
|
|||||||
|
|
||||||
object 私わね extends ISimpleCommand {
|
object 私わね extends ISimpleCommand {
|
||||||
|
|
||||||
override def getName: String = "me"
|
override val name: String = "me"
|
||||||
override def getAliases: Array[String] = Array()
|
override val aliases: Array[ICommandAlias] | Null = null
|
||||||
|
|
||||||
override def execute (command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
if (probabilityTrue(521)) {
|
if (probabilityTrue(521)) {
|
||||||
val text = "/打假"
|
val text = "/打假"
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListenerManager
|
||||||
|
|
||||||
|
object MornyEventListeners {
|
||||||
|
|
||||||
|
def registerAllEvents(): Unit = {
|
||||||
|
|
||||||
|
EventListenerManager.register(
|
||||||
|
// ACTIVITY_RECORDER
|
||||||
|
OnUpdateTimestampOffsetLock,
|
||||||
|
// KUOHUANHUAN_NEED_SLEEP
|
||||||
|
OnTelegramCommand,
|
||||||
|
OnUniMeowTrigger,
|
||||||
|
OnUserRandom,
|
||||||
|
OnQuestionMarkReply,
|
||||||
|
OnUserSlashAction,
|
||||||
|
OnInlineQuery,
|
||||||
|
OnCallMe,
|
||||||
|
OnCallMsgSend,
|
||||||
|
OnMedicationNotifyApply,
|
||||||
|
OnEventHackHandle
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,7 +15,7 @@ object OnCallMe extends EventListener {
|
|||||||
|
|
||||||
private val me = MornyCoeur.config.trustedMaster
|
private val me = MornyCoeur.config.trustedMaster
|
||||||
|
|
||||||
override def onMessage (update: Update): Boolean = {
|
override def onMessage (using update: Update): Boolean = {
|
||||||
|
|
||||||
if update.message.text == null then return false
|
if update.message.text == null then return false
|
||||||
if update.message.chat.`type` != (Chat.Type Private) then return false
|
if update.message.chat.`type` != (Chat.Type Private) then return false
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||||
|
import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity, Update}
|
||||||
|
import com.pengrad.telegrambot.model.request.ParseMode
|
||||||
|
import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker}
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import scala.language.postfixOps
|
||||||
|
import scala.util.matching.Regex
|
||||||
|
|
||||||
|
object OnCallMsgSend extends EventListener {
|
||||||
|
|
||||||
|
private val REGEX_MSG_SENDREQ_DATA_HEAD: Regex = "^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$"r
|
||||||
|
|
||||||
|
case class MessageToSend (
|
||||||
|
message: String|Null,
|
||||||
|
entities: Array[MessageEntity]|Null,
|
||||||
|
parseMode: ParseMode|Null,
|
||||||
|
targetId: Long
|
||||||
|
) {
|
||||||
|
def toSendMessage (target_override: Long|Null = null): SendMessage =
|
||||||
|
val useTarget = if target_override == null then targetId else target_override
|
||||||
|
val sendMessage = SendMessage(useTarget, message)
|
||||||
|
if entities ne null then sendMessage.entities(entities:_*)
|
||||||
|
if parseMode ne null then sendMessage.parseMode(parseMode)
|
||||||
|
sendMessage
|
||||||
|
}
|
||||||
|
private object MessageToSend:
|
||||||
|
def from (raw: Message): MessageToSend = {
|
||||||
|
raw.text match
|
||||||
|
case REGEX_MSG_SENDREQ_DATA_HEAD(_target, _parseMode, _body) =>
|
||||||
|
val target = _target toLong
|
||||||
|
val parseMode: ParseMode | Null = _parseMode match
|
||||||
|
case "*markdown" | "*md" | "*m↓" => ParseMode MarkdownV2
|
||||||
|
case "*md1" => ParseMode Markdown
|
||||||
|
case "*html" => ParseMode HTML
|
||||||
|
case _ => null
|
||||||
|
val bodyOffset = "*msg".length + _target.length + (if _parseMode eq null then 0 else _parseMode.length) + 1
|
||||||
|
val entities = ArrayBuffer.empty[MessageEntity]
|
||||||
|
if (raw.entities ne null) for (e <- raw.entities)
|
||||||
|
val _parsed = MessageEntity(e.`type`, e.offset - bodyOffset, e.length)
|
||||||
|
if e.url ne null then _parsed.url(e.url)
|
||||||
|
if e.user ne null then _parsed.user(e.user)
|
||||||
|
if e.language ne null then _parsed.language(e.language)
|
||||||
|
entities += _parsed
|
||||||
|
MessageToSend(_body, entities toArray, parseMode, target)
|
||||||
|
case _ => null
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onMessage (using update: Update): Boolean = {
|
||||||
|
|
||||||
|
val message = update.message
|
||||||
|
|
||||||
|
if message.chat.`type` != Chat.Type.Private then return false
|
||||||
|
if message.text eq null then return false
|
||||||
|
if !(message.text startsWith "*msg") then return false
|
||||||
|
|
||||||
|
if (!(MornyCoeur.trustedInstance isTrusted message.from.id))
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
message.chat.id,
|
||||||
|
TelegramStickers ID_403
|
||||||
|
).replyToMessageId(message.messageId)
|
||||||
|
return true
|
||||||
|
|
||||||
|
if (message.text == "*msgsend") {
|
||||||
|
|
||||||
|
if (message.replyToMessage eq null) return answer404
|
||||||
|
val messageToSend = MessageToSend from message.replyToMessage
|
||||||
|
if ((messageToSend eq null) || (messageToSend.message eq null)) return answer404
|
||||||
|
val sendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage()
|
||||||
|
|
||||||
|
if (sendResponse isOk) {
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
update.message.chat.id,
|
||||||
|
TelegramStickers ID_SENT
|
||||||
|
).replyToMessageId(update.message.messageId)
|
||||||
|
} else {
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
update.message.chat.id,
|
||||||
|
// language=html
|
||||||
|
s"""<b><u>${sendResponse.errorCode} FAILED</u></b>
|
||||||
|
|<code>${sendResponse.description}</code>"""
|
||||||
|
.stripMargin
|
||||||
|
).replyToMessageId(update.message.messageId).parseMode(ParseMode HTML)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageToSend: MessageToSend =
|
||||||
|
val raw: Message =
|
||||||
|
if (message.text == "*msg")
|
||||||
|
if message.replyToMessage eq null then return answer404
|
||||||
|
else message.replyToMessage
|
||||||
|
else if (message.text startsWith "*msg")
|
||||||
|
message
|
||||||
|
else return answer404
|
||||||
|
val _toSend = MessageToSend from raw
|
||||||
|
if _toSend eq null then return answer404
|
||||||
|
else _toSend
|
||||||
|
|
||||||
|
val targetChatResponse = MornyCoeur.getAccount execute GetChat(messageToSend.targetId)
|
||||||
|
if (targetChatResponse isOk) {
|
||||||
|
def getChatDescriptionHTML (chat: Chat): String =
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||||
|
val _c = TGToString as chat
|
||||||
|
// language=html
|
||||||
|
s"""<i><u>${h(chat.id toString)}</u>@${h(chat.`type`.name)}</i>${if (chat.`type` != Chat.Type.Private) ":::" else ""}
|
||||||
|
|${_c getTypeTag} <b>${h(_c getSafeName)}</b> ${_c getSafeLinkHTML}"""
|
||||||
|
.stripMargin
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
update.message.chat.id,
|
||||||
|
getChatDescriptionHTML(targetChatResponse.chat)
|
||||||
|
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||||
|
} else {
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
update.message.chat.id,
|
||||||
|
// language=html
|
||||||
|
s"""<b><u>${targetChatResponse.errorCode} FAILED</u></b>
|
||||||
|
|<code>${targetChatResponse.description}</code>"""
|
||||||
|
.stripMargin
|
||||||
|
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if messageToSend.message eq null then return true
|
||||||
|
val testSendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage(update.message.chat.id)
|
||||||
|
.replyToMessageId(update.message.messageId)
|
||||||
|
if (!(testSendResponse isOk))
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
update.message.chat.id,
|
||||||
|
// language=html
|
||||||
|
s"""<b><u>${testSendResponse.errorCode}</u> FAILED</b>
|
||||||
|
|<code>${testSendResponse.description}</code>"""
|
||||||
|
.stripMargin
|
||||||
|
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private def answer404 (using update: Update): Boolean =
|
||||||
|
MornyCoeur.extra exec SendSticker(
|
||||||
|
update.message.chat.id,
|
||||||
|
TelegramStickers ID_404
|
||||||
|
).replyToMessageId(update.message.messageId)
|
||||||
|
true
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
import cc.sukazyo.cono.morny.Log.logger
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
import com.pengrad.telegrambot.model.request.ParseMode
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
object OnEventHackHandle extends EventListener {
|
||||||
|
|
||||||
|
private case class Hacker (from_chat: Long, from_message: Long):
|
||||||
|
override def toString: String = s"$from_chat/$from_message"
|
||||||
|
enum HackType:
|
||||||
|
case USER
|
||||||
|
case GROUP
|
||||||
|
case ANY
|
||||||
|
|
||||||
|
private val hackers = mutable.HashMap.empty[String, Hacker]
|
||||||
|
|
||||||
|
def registerHack (from_message: Long, from_user: Long, from_chat: Long, t: HackType): Unit =
|
||||||
|
val record = t match
|
||||||
|
case HackType.USER => s"(($from_user))"
|
||||||
|
case HackType.GROUP => s"{{$from_chat}}"
|
||||||
|
case HackType.ANY => "[[]]"
|
||||||
|
hackers += (record -> Hacker(from_chat, from_message))
|
||||||
|
logger debug s"add hacker track $record"
|
||||||
|
|
||||||
|
private def onEventHacked (chat: Long, fromUser: Long)(using update: Update): Boolean = {
|
||||||
|
logger debug s"got event signed {{$chat}}(($fromUser))"
|
||||||
|
val x: Hacker =
|
||||||
|
if hackers contains s"(($fromUser))" then (hackers remove s"(($fromUser))")get
|
||||||
|
else if hackers contains s"{{$chat}}" then (hackers remove s"{{$chat}}")get
|
||||||
|
else if hackers contains "[[]]" then (hackers remove "[[]]")get
|
||||||
|
else return false
|
||||||
|
logger debug s"hacked event by $x"
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
x.from_chat,
|
||||||
|
// language=html
|
||||||
|
s"<code>${h(GsonBuilder().setPrettyPrinting().create.toJson(update))}</code>"
|
||||||
|
).parseMode(ParseMode HTML).replyToMessageId(x.from_message toInt)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onMessage (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.message.chat.id, update.message.from.id)
|
||||||
|
override def onEditedMessage (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.editedMessage.chat.id, update.editedMessage.from.id)
|
||||||
|
override def onChannelPost (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.channelPost.chat.id, update.channelPost.from.id)
|
||||||
|
override def onEditedChannelPost (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.editedChannelPost.chat.id, update.editedChannelPost.from.id)
|
||||||
|
override def onInlineQuery (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.inlineQuery.from.id)
|
||||||
|
override def onChosenInlineResult (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.chosenInlineResult.from.id)
|
||||||
|
override def onCallbackQuery (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.callbackQuery.from.id)
|
||||||
|
override def onShippingQuery (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.shippingQuery.from.id)
|
||||||
|
override def onPreCheckoutQuery (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.preCheckoutQuery.from.id)
|
||||||
|
override def onPoll (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, 0)
|
||||||
|
override def onPollAnswer (using update: Update): Boolean =
|
||||||
|
onEventHacked(0, update.pollAnswer.user.id)
|
||||||
|
override def onMyChatMemberUpdated (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.myChatMember.chat.id, update.myChatMember.from.id)
|
||||||
|
override def onChatMemberUpdated (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.chatMember.chat.id, update.chatMember.from.id)
|
||||||
|
override def onChatJoinRequest (using update: Update): Boolean =
|
||||||
|
onEventHacked(update.chatJoinRequest.chat.id, update.chatJoinRequest.from.id)
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.event
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.MornyCoeur
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
import cc.sukazyo.cono.morny.bot.api.{EventListener, InlineQueryUnit}
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
import com.pengrad.telegrambot.model.request.InlineQueryResult
|
import com.pengrad.telegrambot.model.request.InlineQueryResult
|
||||||
import com.pengrad.telegrambot.request.AnswerInlineQuery
|
import com.pengrad.telegrambot.request.AnswerInlineQuery
|
||||||
@ -12,12 +13,12 @@ import scala.reflect.ClassTag
|
|||||||
|
|
||||||
object OnInlineQuery extends EventListener {
|
object OnInlineQuery extends EventListener {
|
||||||
|
|
||||||
override def onInlineQuery (update: Update): Boolean = {
|
override def onInlineQuery (using update: Update): Boolean = {
|
||||||
|
|
||||||
val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update
|
val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update
|
||||||
|
|
||||||
var cacheTime = Int.MaxValue
|
var cacheTime = Int.MaxValue
|
||||||
var isPersonal = InlineQueryUnit.DEFAULT_INLINE_PERSONAL_RESP
|
var isPersonal = InlineQueryUnit.defaults.IS_PERSONAL
|
||||||
val resultAnswers = ListBuffer[InlineQueryResult[_]]()
|
val resultAnswers = ListBuffer[InlineQueryResult[_]]()
|
||||||
for (r <- results) {
|
for (r <- results) {
|
||||||
if (cacheTime > r.cacheTime) cacheTime = r.cacheTime
|
if (cacheTime > r.cacheTime) cacheTime = r.cacheTime
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.daemon.MornyDaemons
|
||||||
|
import com.pengrad.telegrambot.model.{Message, Update}
|
||||||
|
|
||||||
|
object OnMedicationNotifyApply extends EventListener {
|
||||||
|
|
||||||
|
override def onEditedMessage (using event: Update): Boolean =
|
||||||
|
editedMessageProcess(event.editedMessage)
|
||||||
|
override def onEditedChannelPost (using event: Update): Boolean =
|
||||||
|
editedMessageProcess(event.editedChannelPost)
|
||||||
|
|
||||||
|
private def editedMessageProcess (edited: Message): Boolean = {
|
||||||
|
if edited.chat.id != MornyCoeur.config.medicationNotifyToChat then return false
|
||||||
|
MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
object OnQuestionMarkReply extends EventListener {
|
||||||
|
|
||||||
|
private def QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓')
|
||||||
|
|
||||||
|
override def onMessage (using event: Update): Boolean = {
|
||||||
|
|
||||||
|
if event.message.text eq null then return false
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue
|
||||||
|
if !probabilityTrue(8) then return false
|
||||||
|
for (c <- event.message.text toCharArray)
|
||||||
|
if !(QUESTION_MARKS contains c) then return false
|
||||||
|
|
||||||
|
MornyCoeur.extra exec SendMessage(
|
||||||
|
event.message.chat.id, event.message.text
|
||||||
|
).replyToMessageId(event.message.messageId)
|
||||||
|
true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import com.pengrad.telegrambot.model.{Message, Update}
|
||||||
|
import cc.sukazyo.cono.morny.Log.logger
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.bot.command.MornyCommands
|
||||||
|
|
||||||
|
object OnTelegramCommand extends EventListener {
|
||||||
|
|
||||||
|
override def onMessage (using update: Update): Boolean = {
|
||||||
|
|
||||||
|
def _isCommandMessage(message: Message): Boolean =
|
||||||
|
if message.text eq null then false
|
||||||
|
else if !(message.text startsWith "/") then false
|
||||||
|
else if message.text startsWith "/ " then false
|
||||||
|
else true
|
||||||
|
|
||||||
|
if !_isCommandMessage(update.message) then return false
|
||||||
|
val inputCommand = InputCommand(update.message.text drop 1)
|
||||||
|
if (!(inputCommand.getCommand matches "^\\w+$"))
|
||||||
|
logger debug "not command"
|
||||||
|
false
|
||||||
|
else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.getUsername))
|
||||||
|
logger debug "not morny command"
|
||||||
|
false
|
||||||
|
else
|
||||||
|
logger debug "is command"
|
||||||
|
MornyCommands.execute(using inputCommand)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.bot.command.MornyCommands
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
object OnUniMeowTrigger extends EventListener {
|
||||||
|
|
||||||
|
override def onMessage (using update: Update): Boolean = {
|
||||||
|
|
||||||
|
if update.message.text eq null then return false
|
||||||
|
var ok = false
|
||||||
|
for ((name, command) <- MornyCommands.commands_uni)
|
||||||
|
val _name = "/"+name
|
||||||
|
if (_name == update.message.text)
|
||||||
|
command.execute(using InputCommand(_name))
|
||||||
|
ok = true
|
||||||
|
ok
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||||
|
import cc.sukazyo.cono.morny.MornyCoeur
|
||||||
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
object OnUpdateTimestampOffsetLock extends EventListener {
|
||||||
|
|
||||||
|
private def isOutdated (timestamp: Int): Boolean =
|
||||||
|
timestamp < (MornyCoeur.config.eventOutdatedTimestamp/1000)
|
||||||
|
|
||||||
|
override def onMessage (using update: Update): Boolean = isOutdated(update.message.date)
|
||||||
|
override def onEditedMessage (using update: Update): Boolean = isOutdated(update.editedMessage.date)
|
||||||
|
override def onChannelPost (using update: Update): Boolean = isOutdated(update.channelPost.date)
|
||||||
|
override def onEditedChannelPost (using update: Update): Boolean = isOutdated(update.editedChannelPost.date)
|
||||||
|
|
||||||
|
}
|
@ -12,7 +12,7 @@ object OnUserRandom extends EventListener {
|
|||||||
private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r
|
private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r
|
||||||
private val USER_IF_QUERY = "(.+)[吗?|?]+$"r
|
private val USER_IF_QUERY = "(.+)[吗?|?]+$"r
|
||||||
|
|
||||||
override def onMessage(update: Update): Boolean = {
|
override def onMessage(using update: Update): Boolean = {
|
||||||
|
|
||||||
if update.message.text == null then return false
|
if update.message.text == null then return false
|
||||||
if update.message.text startsWith "/" then return false
|
if update.message.text startsWith "/" then return false
|
||||||
|
@ -15,9 +15,9 @@ object OnUserSlashAction extends EventListener {
|
|||||||
|
|
||||||
private val TG_FORMAT = "^\\w+(@\\w+)?$"r
|
private val TG_FORMAT = "^\\w+(@\\w+)?$"r
|
||||||
|
|
||||||
override def onMessage (update: Update): Boolean = {
|
override def onMessage (using update: Update): Boolean = {
|
||||||
|
|
||||||
val text = update.message.text;
|
val text = update.message.text
|
||||||
if text == null then return false
|
if text == null then return false
|
||||||
|
|
||||||
if (text startsWith "/") {
|
if (text startsWith "/") {
|
||||||
@ -31,6 +31,7 @@ object OnUserSlashAction extends EventListener {
|
|||||||
case TG_FORMAT(_) =>
|
case TG_FORMAT(_) =>
|
||||||
return false
|
return false
|
||||||
case x if x contains "/" => return false
|
case x if x contains "/" => return false
|
||||||
|
case _ =>
|
||||||
|
|
||||||
val isHardParse = actions(0) isBlank
|
val isHardParse = actions(0) isBlank
|
||||||
def hp_len(i: Int) = if isHardParse then i+1 else i
|
def hp_len(i: Int) = if isHardParse then i+1 else i
|
||||||
@ -39,7 +40,7 @@ object OnUserSlashAction extends EventListener {
|
|||||||
val hasObject = actions.length != hp_len(1)
|
val hasObject = actions.length != hp_len(1)
|
||||||
val v_object =
|
val v_object =
|
||||||
if hasObject then
|
if hasObject then
|
||||||
actions slice(hp_len(1), actions.length) mkString(" ")
|
actions slice(hp_len(1), actions.length) mkString " "
|
||||||
else ""
|
else ""
|
||||||
val origin = update.message
|
val origin = update.message
|
||||||
val target =
|
val target =
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
import javax.annotation.Nullable
|
import javax.annotation.Nullable
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
trait ITelegramQuery {
|
trait ITelegramQuery {
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit.defaults
|
||||||
|
import com.pengrad.telegrambot.model.request.InlineQueryResult
|
||||||
|
|
||||||
|
object InlineQueryUnit {
|
||||||
|
|
||||||
|
object defaults:
|
||||||
|
val CACHE_TIME = 300
|
||||||
|
val IS_PERSONAL = false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InlineQueryUnit[T <: InlineQueryResult[T]](val result: T) {
|
||||||
|
|
||||||
|
var cacheTime: Int = defaults.CACHE_TIME
|
||||||
|
var isPersonal: Boolean = defaults.IS_PERSONAL
|
||||||
|
|
||||||
|
def cacheTime (v: Int): InlineQueryUnit[T] =
|
||||||
|
this.cacheTime = v
|
||||||
|
this
|
||||||
|
|
||||||
|
def isPersonal (v: Boolean): InlineQueryUnit[T] =
|
||||||
|
this.isPersonal = v
|
||||||
|
this
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import cc.sukazyo.cono.morny.bot.query
|
import cc.sukazyo.cono.morny.bot.query
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent}
|
import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.Log.logger
|
import cc.sukazyo.cono.morny.Log.logger
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import cc.sukazyo.cono.morny.util.BiliTool
|
import cc.sukazyo.cono.morny.util.BiliTool
|
||||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.query
|
package cc.sukazyo.cono.morny.bot.query
|
||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle
|
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle
|
||||||
|
|
||||||
|
17
src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala
Normal file
17
src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package cc.sukazyo.cono.morny.data
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.model.User
|
||||||
|
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
object MornyJrrp {
|
||||||
|
|
||||||
|
def jrrp_of_telegramUser (user: User, timestamp: Long): Double =
|
||||||
|
jrrp_v_xmomi(user.id, timestamp/(1000*60*60*24)) * 100.0
|
||||||
|
|
||||||
|
private def jrrp_v_xmomi (identifier: Long, dayStamp: Long): Double =
|
||||||
|
import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex
|
||||||
|
import cc.sukazyo.cono.morny.util.CommonEncrypt.hashMd5
|
||||||
|
(java.lang.Long parseLong byteArrayToHex(hashMd5(s"$identifier@$dayStamp")).substring(0, 4)) / (0xffff toDouble)
|
||||||
|
|
||||||
|
}
|
37
src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala
Normal file
37
src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package cc.sukazyo.cono.morny.data
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import okhttp3.{OkHttpClient, Request, RequestBody, ResponseBody}
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
import scala.util.Using
|
||||||
|
|
||||||
|
object NbnhhshQuery {
|
||||||
|
|
||||||
|
case class Word (name: String, trans: Array[String], inputting: Array[String])
|
||||||
|
case class GuessResult (words: Array[Word])
|
||||||
|
|
||||||
|
private case class GuessRequest (text: String)
|
||||||
|
|
||||||
|
private val API_URL = "https://lab.magiconch.com/api/nbnhhsh/"
|
||||||
|
private val API_GUESS_METHOD = "guess/"
|
||||||
|
|
||||||
|
private val httpClient = OkHttpClient()
|
||||||
|
|
||||||
|
@throws[IOException]
|
||||||
|
def sendGuess (text: String): GuessResult = {
|
||||||
|
val requestJsonText = Gson().toJson(GuessRequest(text))
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(API_URL + API_GUESS_METHOD)
|
||||||
|
.post(RequestBody.create(requestJsonText, MediaTypes.JSON))
|
||||||
|
.build
|
||||||
|
Using (httpClient.newCall(request).execute) { response =>
|
||||||
|
val body = response.body
|
||||||
|
if body eq null then throw IOException("Nbnhhsh Request: body is null.")
|
||||||
|
val x = s"{ 'words': ${body.string} }"
|
||||||
|
Gson().fromJson(x, classOf[GuessResult])
|
||||||
|
}.get
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,12 +30,11 @@ object IP186QueryHandler {
|
|||||||
@throws[IOException]
|
@throws[IOException]
|
||||||
private def commonQuery (requestUrl: String, queryParam: String): IP186Response = {
|
private def commonQuery (requestUrl: String, queryParam: String): IP186Response = {
|
||||||
val request = Request.Builder().url(requestUrl + "?" + queryParam).build
|
val request = Request.Builder().url(requestUrl + "?" + queryParam).build
|
||||||
var _body_string: String|Null = null
|
|
||||||
Using ((httpClient newCall request) execute) { response =>
|
Using ((httpClient newCall request) execute) { response =>
|
||||||
if response.body ne null then _body_string = response.body.string
|
val _body = response.body
|
||||||
}
|
if _body eq null then throw IOException("Response of ip186: body is empty!")
|
||||||
if _body_string eq null then throw IOException("Response of ip186: body is empty!")
|
IP186Response(requestUrl, _body.string)
|
||||||
IP186Response(requestUrl, _body_string)
|
}.get
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user