Compare commits

...

2 Commits

75 changed files with 551 additions and 220 deletions

View File

@ -37,6 +37,9 @@ object MornyCoeur {
userid: Long, userid: Long,
tasks: Scheduler, tasks: Scheduler,
trusted: MornyTrusted, trusted: MornyTrusted,
eventManager: EventListenerManager,
commandManager: MornyCommandManager,
queryManager: MornyQueryManager,
givenCxt: GivenContext givenCxt: GivenContext
) )
@ -153,19 +156,45 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
/** current Morny's [[MornyTrusted]] instance */ /** current Morny's [[MornyTrusted]] instance */
val trusted: MornyTrusted = MornyTrusted() val trusted: MornyTrusted = MornyTrusted()
modules.foreach(it => it.onInitializingPre(OnInitializingPreContext(
externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted,
initializeContext)))
val daemons: MornyDaemons = MornyDaemons() val daemons: MornyDaemons = MornyDaemons()
initializeContext << daemons initializeContext << daemons
val eventManager: EventListenerManager = EventListenerManager() val eventManager: EventListenerManager = EventListenerManager()
eventManager register MornyOnUpdateTimestampOffsetLock()
val commands: MornyCommandManager = MornyCommandManager() val commands: MornyCommandManager = MornyCommandManager()
val queries: MornyQueryManager = MornyQueryManager() val queries: MornyQueryManager = MornyQueryManager()
// Coeur Initializing Pre Event
modules.foreach(it => it.onInitializingPre(OnInitializingPreContext(
externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted,
eventManager, commands, queries,
initializeContext)))
// register core/api events
eventManager register MornyOnUpdateTimestampOffsetLock()
eventManager register MornyOnTelegramCommand(using commands) eventManager register MornyOnTelegramCommand(using commands)
eventManager register MornyOnInlineQuery(using queries) eventManager register MornyOnInlineQuery(using queries)
{ // register core commands
import bot.command.*
val $MornyHellos = MornyHellos()
val $MornyInformation = MornyInformation()
val $MornyInformationOlds = MornyInformationOlds(using $MornyInformation)
val $MornyManagers = MornyManagers()
commands.register(
$MornyHellos.On,
$MornyHellos.Hello,
MornyInfoOnStart(),
$MornyManagers.SaveData,
$MornyInformation,
$MornyInformationOlds.Version,
$MornyInformationOlds.Runtime,
$MornyManagers.Exit,
DirectMsgClear(),
)
}
// Coeur Initializing Event // Coeur Initializing Event
modules.foreach(it => it.onInitializing(OnInitializingContext( modules.foreach(it => it.onInitializing(OnInitializingContext(
@ -175,7 +204,6 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
initializeContext))) initializeContext)))
eventManager register daemons.reporter.EventStatistics.EventInfoCatcher eventManager register daemons.reporter.EventStatistics.EventInfoCatcher
val watchDog: WatchDog = WatchDog("watch-dog", 1000, 1500, { (consumed, _) => val watchDog: WatchDog = WatchDog("watch-dog", 1000, 1500, { (consumed, _) =>
import cc.sukazyo.cono.morny.util.CommonFormat.formatDuration as f import cc.sukazyo.cono.morny.util.CommonFormat.formatDuration as f
logger warn logger warn
@ -184,6 +212,8 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
tasks.notifyIt() tasks.notifyIt()
}) })
initializeContext / this << watchDog initializeContext / this << watchDog
// Coeur Initializing Post Event
modules.foreach(it => it.onInitializingPost(OnInitializingPostContext( modules.foreach(it => it.onInitializingPost(OnInitializingPostContext(
externalContext, externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted, coeurStartTimestamp, account, username, userid, tasks, trusted,
@ -197,11 +227,13 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
logger info "done test run, exiting." logger info "done test run, exiting."
this.exit(0, TestRun) this.exit(0, TestRun)
// Coeur Starting Pre
configure_exitCleanup() configure_exitCleanup()
// put things that need to cleanup when exit below
// so that it will be correctly cleanup when normal run and will not execute in testRun. // Coeur Starting Event
modules.foreach(it => it.onStarting(OnStartingContext( modules.foreach(it => it.onStarting(OnStartingContext(
initializeContext))) initializeContext)))
daemons.start() daemons.start()
logger info "start telegram event listening" logger info "start telegram event listening"
import com.pengrad.telegrambot.TelegramException import com.pengrad.telegrambot.TelegramException
@ -250,6 +282,8 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
} }
}) })
// Coeur Starting Post Event
modules.foreach(it => it.onStartingPost(OnStartingPostContext( modules.foreach(it => it.onStartingPost(OnStartingPostContext(
initializeContext))) initializeContext)))
@ -270,14 +304,15 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
private def exitCleanup (): Unit = { private def exitCleanup (): Unit = {
daemons.reporter.reportCoeurExit() daemons.reporter.reportCoeurExit()
modules.foreach(it => it.onExiting)
account.shutdown() account.shutdown()
logger info "stopped bot account" logger info "stopped bot account"
modules.foreach(it => it.onExit)
daemons.stop() daemons.stop()
tasks.waitForStop() tasks.waitForStop()
logger info s"morny tasks stopped: remains ${tasks.amount} tasks not be executed" logger info s"morny tasks stopped: remains ${tasks.amount} tasks not be executed"
if config.commandLogoutClear then if config.commandLogoutClear then
commands.automaticTGListRemove() commands.automaticTGListRemove()
modules.foreach(it => it.onExited)
logger info "done exit cleanup" logger info "done exit cleanup"
} }

View File

@ -1,84 +0,0 @@
package cc.sukazyo.cono.morny
import cc.sukazyo.cono.morny.MornyCoeur.OnInitializingContext
class MornyCoreModule extends MornyModule {
override val id: String = "cc.sukazyo.cono.morny.bot"
override val name: String = "Morny Coeur - Core (for refactor temporary)"
override val version: String = MornySystem.VERSION
override val description: String | Null =
"""Core module of Morny Coeur.
|
|Exists for temporary use, when refactor completed it should be replaced
|by all other small modules that provide different functionality.
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: OnInitializingContext): Unit = {
import cc.sukazyo.cono.morny.bot.command.*
import cc.sukazyo.cono.morny.bot.event.*
import cc.sukazyo.cono.morny.bot.query.*
import cxt.*
val $OnUserRandom = OnUserRandom()
eventManager.register(
// ACTIVITY_RECORDER
// KUOHUANHUAN_NEED_SLEEP
$OnUserRandom.RandomSelect,
//noinspection NonAsciiCharacters
$OnUserRandom.尊嘟假嘟,
OnQuestionMarkReply(),
OnUserSlashAction(),
OnCallMe(),
OnCallMsgSend(),
OnGetSocial(),
OnMedicationNotifyApply(),
OnEventHackHandle()
)
val $MornyHellos = MornyHellos()
val $IP186Query = IP186Query()
val $MornyInformation = MornyInformation()
val $MornyInformationOlds = MornyInformationOlds(using $MornyInformation)
val $MornyManagers = MornyManagers()
//noinspection NonAsciiCharacters
val $创 = ()
commandManager.register(
$MornyHellos.On,
$MornyHellos.Hello,
MornyInfoOnStart(),
GetUsernameAndId(),
EventHack(),
Nbnhhsh(),
$IP186Query.IP,
$IP186Query.Whois,
Encryptor(),
MornyOldJrrp(),
GetSocial(),
$MornyManagers.SaveData,
$MornyInformation,
$MornyInformationOlds.Version,
$MornyInformationOlds.Runtime,
$MornyManagers.Exit,
Testing(),
DirectMsgClear(),
//noinspection NonAsciiCharacters
$创.Chuang
)
queryManager.register(
RawText(),
MyInformation(),
ShareToolTwitter(),
ShareToolBilibili(),
ShareToolSocialContent()
)
}
}

View File

@ -19,6 +19,7 @@ trait MornyModule {
def onRoutineSavingData (using MornyCoeur): Unit = {} def onRoutineSavingData (using MornyCoeur): Unit = {}
def onExit (using MornyCoeur): Unit = {} def onExiting (using MornyCoeur): Unit = {}
def onExited (using MornyCoeur): Unit = {}
} }

View File

@ -0,0 +1,25 @@
package cc.sukazyo.cono.morny
object ServerModulesLoader {
def load (): List[MornyModule] = {
List(
tele_utils.ModuleTeleUtils(),
randomize_somthing.ModuleRandomize(),
slash_action.ModuleSlashAction(),
nbnhhsh.ModuleNbnhhsh(),
ip186.ModuleIP186(),
encrypt_tool.ModuleEncryptor(),
call_me.ModuleCallMe(),
social_share.ModuleSocialShare(),
medication_timer.ModuleMedicationTimer(),
morny_misc.ModuleMornyMisc(),
uni_meow.ModuleUniMeow()
)
}
}

View File

@ -25,13 +25,6 @@ class MornyCommandManager (using coeur: MornyCoeur) {
for (alias <- i.aliases) for (alias <- i.aliases)
this.commands += (alias.name -> i) this.commands += (alias.name -> i)
private[bot] val commands_uni: CommandMap = mutable.SeqMap.empty
def registerForUni [T <: ISimpleCommand] (commands: T*): Unit =
for (i <- commands)
this.commands_uni += (i.name -> i)
for (alias <- i.aliases)
this.commands_uni += (alias.name -> i)
def execute (using command: InputCommand, event: Update): Boolean = { def execute (using command: InputCommand, event: Update): Boolean = {
if (commands contains command.command) if (commands contains command.command)
commands(command.command) execute; commands(command.command) execute;

View File

@ -0,0 +1,22 @@
package cc.sukazyo.cono.morny.call_me
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleCallMe extends MornyInternalModule {
override val id: String = "morny.call_me"
override val name: String = "Morny Can Call Master"
override val description: String | Null =
"""Provides a serial private message handler that can talk with Morny's Master
|inside the Morny bot PM.""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
eventManager register OnCallMe()
eventManager register OnCallMsgSend()
}
}

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.call_me
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}

View File

@ -1,10 +1,10 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.call_me
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity, Update} import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity}
import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.request.ParseMode
import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker} import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker}

View File

@ -5,15 +5,12 @@ import cc.sukazyo.cono.morny.MornyCoeur
class MornyDaemons (using val coeur: MornyCoeur) { class MornyDaemons (using val coeur: MornyCoeur) {
val medicationTimer: MedicationTimer = MedicationTimer()
val reporter: MornyReport = MornyReport() val reporter: MornyReport = MornyReport()
val eventHack: EventHacker = EventHacker()
def start (): Unit = { def start (): Unit = {
logger notice "ALL Morny Daemons starting..." logger notice "ALL Morny Daemons starting..."
medicationTimer.start()
reporter.start() reporter.start()
logger notice "Morny Daemons started." logger notice "Morny Daemons started."
@ -24,7 +21,6 @@ class MornyDaemons (using val coeur: MornyCoeur) {
logger notice "stopping All Morny Daemons..." logger notice "stopping All Morny Daemons..."
medicationTimer.stop()
reporter.stop() reporter.stop()
logger notice "stopped ALL Morny Daemons." logger notice "stopped ALL Morny Daemons."

View File

@ -1,7 +1,8 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.encrypt_tool
import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.Log.logger
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand

View File

@ -0,0 +1,20 @@
package cc.sukazyo.cono.morny.encrypt_tool
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleEncryptor extends MornyInternalModule {
override val id: String = "morny.encrypt"
override val name: String = "Morny Encrypt Tools"
override val description: String | Null =
// language=markdown
"""Provides `/encrypt` command for enc/dec/hash things.
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
commandManager register Encryptor()
}
}

View File

@ -0,0 +1,9 @@
package cc.sukazyo.cono.morny.internal
import cc.sukazyo.cono.morny.{MornyModule, MornySystem}
trait MornyInternalModule extends MornyModule {
override val version: String = MornySystem.VERSION
}

View File

@ -1,7 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.ip186
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.extra.ip186.IP186QueryHandler import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update
@ -10,7 +10,7 @@ import com.pengrad.telegrambot.request.SendMessage
import scala.language.postfixOps import scala.language.postfixOps
class IP186Query (using coeur: MornyCoeur) { class BotCommand (using coeur: MornyCoeur) {
private enum Subs (val cmd: String): private enum Subs (val cmd: String):
case IP extends Subs("ip") case IP extends Subs("ip")

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.ip186 package cc.sukazyo.cono.morny.ip186
import cc.sukazyo.cono.morny.util.SttpPublic.{mornyBasicRequest, Schemes} import cc.sukazyo.cono.morny.util.SttpPublic.{mornyBasicRequest, Schemes}
import sttp.client3.{asString, HttpError, SttpClientException, UriContext} import sttp.client3.{asString, HttpError, SttpClientException, UriContext}

View File

@ -1,3 +1,3 @@
package cc.sukazyo.cono.morny.extra.ip186 package cc.sukazyo.cono.morny.ip186
case class IP186Response (url: String, body: String) case class IP186Response (url: String, body: String)

View File

@ -0,0 +1,24 @@
package cc.sukazyo.cono.morny.ip186
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleIP186 extends MornyInternalModule {
override val id: String = "morny.ext.ip186"
override val name: String = "Morny ip.186 support"
override val description: String | Null =
// language=markdown
"""Provides `/ip` and `/markdown` commands, using ip.186516.xyz as query backend.
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
val $command = BotCommand()
commandManager.register(
$command.IP,
$command.Whois
)
}
}

View File

@ -1,8 +1,8 @@
package cc.sukazyo.cono.morny.daemon package cc.sukazyo.cono.morny.medication_timer
import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.Log.logger
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.daemon.MedicationTimer.calcNextRoutineTimestamp import cc.sukazyo.cono.morny.medication_timer.MedicationTimer.calcNextRoutineTimestamp
import cc.sukazyo.cono.morny.util.schedule.RoutineTask import cc.sukazyo.cono.morny.util.schedule.RoutineTask
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import cc.sukazyo.cono.morny.util.CommonFormat import cc.sukazyo.cono.morny.util.CommonFormat

View File

@ -0,0 +1,57 @@
package cc.sukazyo.cono.morny.medication_timer
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.Log.logger
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleMedicationTimer extends MornyInternalModule {
override val id: String = "morny.medication_timer"
override val name: String = "Morny Medication Timer"
override val description: String | Null =
"""A notify tool for Morny notify its master to take medication.
|""".stripMargin
override def onInitializingPre (using MornyCoeur)(cxt: MornyCoeur.OnInitializingPreContext): Unit = {
import cxt.*
val instance: MedicationTimer = MedicationTimer()
externalContext << instance
givenCxt << instance
}
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
externalContext >> { (instance: MedicationTimer) =>
eventManager register OnMedicationNotifyApply(using instance)
} || {
logger warn "There seems no Medication Timer instance is provided; skipped register events for it."
}
}
override def onStarting (using coeur: MornyCoeur)(cxt: MornyCoeur.OnStartingContext): Unit = {
import coeur.*
externalContext >> { (instance: MedicationTimer) =>
instance.start()
} || {
logger warn "There seems no Medication Timer instance is provided; skipped start it."
}
}
override def onExiting (using coeur: MornyCoeur): Unit = {
import coeur.*
externalContext >> { (instance: MedicationTimer) =>
instance.stop()
} || {
logger warn "There seems no Medication Timer instance need to be stop."
}
}
}

View File

@ -1,10 +1,10 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.medication_timer
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import com.pengrad.telegrambot.model.Message import com.pengrad.telegrambot.model.Message
class OnMedicationNotifyApply (using coeur: MornyCoeur) extends EventListener { class OnMedicationNotifyApply (using instance: MedicationTimer)(using coeur: MornyCoeur) extends EventListener {
override def onEditedMessage (using event: EventEnv): Unit = override def onEditedMessage (using event: EventEnv): Unit =
editedMessageProcess(event.update.editedMessage) editedMessageProcess(event.update.editedMessage)
@ -13,7 +13,7 @@ class OnMedicationNotifyApply (using coeur: MornyCoeur) extends EventListener {
private def editedMessageProcess (edited: Message)(using event: EventEnv): Unit = { private def editedMessageProcess (edited: Message)(using event: EventEnv): Unit = {
if edited.chat.id != coeur.config.medicationNotifyToChat then return; if edited.chat.id != coeur.config.medicationNotifyToChat then return;
if coeur.daemons.medicationTimer.refreshNotificationWrite(edited) then if instance.refreshNotificationWrite(edited) then
event.setEventOk event.setEventOk
} }

View File

@ -0,0 +1,20 @@
package cc.sukazyo.cono.morny.morny_misc
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleMornyMisc extends MornyInternalModule {
override val id: String = "morny.misc"
override val name: String = "Morny Misc Things"
override val description: String | Null = "Misc things that from old days Morny."
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
commandManager register MornyOldJrrp()
commandManager register Testing()
}
}

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.data package cc.sukazyo.cono.morny.morny_misc
import cc.sukazyo.cono.morny.util.EpochDateTime.{EpochDays, EpochMillis} import cc.sukazyo.cono.morny.util.EpochDateTime.{EpochDays, EpochMillis}
import com.pengrad.telegrambot.model.User import com.pengrad.telegrambot.model.User

View File

@ -1,6 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.morny_misc
import cc.sukazyo.cono.morny.data.MornyJrrp
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.*
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec

View File

@ -1,6 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.morny_misc
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ISimpleCommand}
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update

View File

@ -1,8 +1,8 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.nbnhhsh
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.extra.NbnhhshQuery
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
@ -11,10 +11,9 @@ import com.pengrad.telegrambot.model.request.ParseMode
import com.pengrad.telegrambot.request.{SendMessage, SendSticker} import com.pengrad.telegrambot.request.{SendMessage, SendSticker}
import sttp.client3.{HttpError, SttpClientException} import sttp.client3.{HttpError, SttpClientException}
import java.io.IOException
import scala.language.postfixOps import scala.language.postfixOps
class Nbnhhsh (using coeur: MornyCoeur) extends ITelegramCommand { class CommandNbnhhsh (using coeur: MornyCoeur) extends ITelegramCommand {
private val NBNHHSH_RESULT_HEAD_HTML = private val NBNHHSH_RESULT_HEAD_HTML =
// language=html // language=html

View File

@ -0,0 +1,25 @@
package cc.sukazyo.cono.morny.nbnhhsh
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleNbnhhsh extends MornyInternalModule {
override val id: String = "morny.nbnhhsh"
override val name: String = "Morny Nbnhhsh Query"
override val description: String | Null =
// language=markdown
"""Provides a way to translate text using nbnhhsh(能不能好好说话) API.
|
|- command `/nbnhhsh` for translate input or replied.
|- inline query is still under WIP.
|
|API Url: https://lab.magiconch.com/api/nbnhhsh
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
commandManager register CommandNbnhhsh()
}
}

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra package cc.sukazyo.cono.morny.nbnhhsh
import cc.sukazyo.cono.morny.util.SttpPublic.mornyBasicRequest import cc.sukazyo.cono.morny.util.SttpPublic.mornyBasicRequest
import com.google.gson.Gson import com.google.gson.Gson

View File

@ -0,0 +1,29 @@
package cc.sukazyo.cono.morny.randomize_somthing
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleRandomize extends MornyInternalModule {
override val id: String = "morny.rand"
override val name: String = "Morny Randomize Something"
override val description: String | Null =
// language=markdown
"""Randomize reply something by rand.
|
|Can randomly reply like *尊嘟假嘟*, and provide support for */ $this or $that*,
|and more interesting things.
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
val $OnUserRandom = OnUserRandom()
eventManager register $OnUserRandom.RandomSelect
eventManager register OnQuestionMarkReply()
//noinspection NonAsciiCharacters
eventManager register $OnUserRandom.尊嘟假嘟
}
}

View File

@ -1,8 +1,8 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.randomize_somthing
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.event.OnQuestionMarkReply.isAllMessageMark import cc.sukazyo.cono.morny.randomize_somthing.OnQuestionMarkReply.isAllMessageMark
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.request.SendMessage import com.pengrad.telegrambot.request.SendMessage

View File

@ -1,9 +1,8 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.randomize_somthing
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.Update
import com.pengrad.telegrambot.request.SendMessage import com.pengrad.telegrambot.request.SendMessage
import com.pengrad.telegrambot.response.SendResponse import com.pengrad.telegrambot.response.SendResponse
@ -13,7 +12,6 @@ class OnUserRandom (using coeur: MornyCoeur) {
object RandomSelect extends EventListener { object RandomSelect 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

View File

@ -0,0 +1,24 @@
package cc.sukazyo.cono.morny.slash_action
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleSlashAction extends MornyInternalModule {
override val id: String = "morny.slash"
override val name: String = "Morny SlashBot Support"
override val description: String | Null =
// language=markdown
"""Reply calls like "", "摸摸".
|
|This module requires *Group Privacy* set to `disabled` on the bot account.
|
|(@RongSlashBot)[https://t.me/RongSlashBot]
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
eventManager register OnUserSlashAction()
}
}

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.slash_action
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}

View File

@ -0,0 +1,28 @@
package cc.sukazyo.cono.morny.social_share
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
class ModuleSocialShare extends MornyInternalModule {
override val id: String = "morny.social"
override val name: String = "Morny Social Media Share Tools"
override val description: String | Null =
"""Provides a serial tools contains refactor share url, get content from
|social media, and more.
|""".stripMargin
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
queryManager register query.ShareToolTwitter()
queryManager register query.ShareToolBilibili()
commandManager register command.GetSocial()
eventManager register event.OnGetSocial()
queryManager register query.ShareToolSocialContent()
}
}

View File

@ -1,7 +1,7 @@
package cc.sukazyo.cono.morny.data.social package cc.sukazyo.cono.morny.social_share.api
import cc.sukazyo.cono.morny.data.social.SocialContent.{SocialMedia, SocialMediaType, SocialMediaWithUrl} import cc.sukazyo.cono.morny.social_share.api.SocialContent.{SocialMedia, SocialMediaType, SocialMediaWithUrl}
import cc.sukazyo.cono.morny.data.social.SocialContent.SocialMediaType.{Photo, Video} import cc.sukazyo.cono.morny.social_share.api.SocialContent.SocialMediaType.{Photo, Video}
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec

View File

@ -1,8 +1,8 @@
package cc.sukazyo.cono.morny.data.social package cc.sukazyo.cono.morny.social_share.api
import cc.sukazyo.cono.morny.data.social.SocialContent.{SocialMedia, SocialMediaWithUrl} import cc.sukazyo.cono.morny.social_share.api.SocialContent.{SocialMedia, SocialMediaWithUrl}
import cc.sukazyo.cono.morny.data.social.SocialContent.SocialMediaType.{Photo, Video} import cc.sukazyo.cono.morny.social_share.api.SocialContent.SocialMediaType.{Photo, Video}
import cc.sukazyo.cono.morny.extra.twitter.{FXApi, FXTweet} import cc.sukazyo.cono.morny.social_share.external.twitter.{FXApi, FXTweet}
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
object SocialTwitterParser { object SocialTwitterParser {

View File

@ -1,8 +1,8 @@
package cc.sukazyo.cono.morny.data.social package cc.sukazyo.cono.morny.social_share.api
import cc.sukazyo.cono.morny.data.social.SocialContent.SocialMediaType.Photo import cc.sukazyo.cono.morny.social_share.api.SocialContent.SocialMediaType.Photo
import cc.sukazyo.cono.morny.data.social.SocialContent.SocialMediaWithBytesData import cc.sukazyo.cono.morny.social_share.api.SocialContent.SocialMediaWithBytesData
import cc.sukazyo.cono.morny.extra.weibo.{genWeiboStatusUrl, MApi, MStatus, StatusUrlInfo} import cc.sukazyo.cono.morny.social_share.external.weibo.{genWeiboStatusUrl, MApi, MStatus, StatusUrlInfo}
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.{cleanupHtml as ch, escapeHtml as h} import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.{cleanupHtml as ch, escapeHtml as h}
import io.circe.{DecodingFailure, ParsingFailure} import io.circe.{DecodingFailure, ParsingFailure}
import sttp.client3.{HttpError, SttpClientException} import sttp.client3.{HttpError, SttpClientException}

View File

@ -1,8 +1,10 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.social_share.command
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.event.OnGetSocial import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.social_share.event.OnGetSocial
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update
import com.pengrad.telegrambot.request.SendSticker import com.pengrad.telegrambot.request.SendSticker

View File

@ -1,13 +1,13 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.social_share.event
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.bot.event.OnGetSocial.tryFetchSocial
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.extra.{twitter, weibo} import cc.sukazyo.cono.morny.social_share.event.OnGetSocial.tryFetchSocial
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.Log.{exceptionLog, logger}
import cc.sukazyo.cono.morny.data.social.{SocialTwitterParser, SocialWeiboParser} import cc.sukazyo.cono.morny.social_share.api.{SocialTwitterParser, SocialWeiboParser}
import cc.sukazyo.cono.morny.social_share.external.{twitter, weibo}
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Message.entitiesSafe import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Message.entitiesSafe
import com.pengrad.telegrambot.model.Chat import com.pengrad.telegrambot.model.Chat
import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.request.ParseMode
@ -74,9 +74,9 @@ object OnGetSocial {
} }
def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) =
import cc.sukazyo.cono.morny.social_share.external.twitter.FXApi
import io.circe.{DecodingFailure, ParsingFailure} import io.circe.{DecodingFailure, ParsingFailure}
import sttp.client3.SttpClientException import sttp.client3.SttpClientException
import twitter.FXApi
try { try {
val api = FXApi.Fetch.status(Some(url.screenName), url.statusId) val api = FXApi.Fetch.status(Some(url.screenName), url.statusId)
SocialTwitterParser.parseFXTweet(api).outputToTelegram SocialTwitterParser.parseFXTweet(api).outputToTelegram
@ -90,9 +90,9 @@ object OnGetSocial {
coeur.daemons.reporter.exception(e, "Error on requesting FixTweet API") coeur.daemons.reporter.exception(e, "Error on requesting FixTweet API")
def tryFetchSocialOfWeibo (url: weibo.StatusUrlInfo)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = def tryFetchSocialOfWeibo (url: weibo.StatusUrlInfo)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) =
import cc.sukazyo.cono.morny.social_share.external.weibo.MApi
import io.circe.{DecodingFailure, ParsingFailure} import io.circe.{DecodingFailure, ParsingFailure}
import sttp.client3.{HttpError, SttpClientException} import sttp.client3.{HttpError, SttpClientException}
import weibo.MApi
try { try {
val api = MApi.Fetch.statuses_show(url.id) val api = MApi.Fetch.statuses_show(url.id)
SocialWeiboParser.parseMStatus(api).outputToTelegram SocialWeiboParser.parseMStatus(api).outputToTelegram

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.util package cc.sukazyo.cono.morny.social_share.external.bilibili
import cc.sukazyo.cono.morny.util.UseMath.** import cc.sukazyo.cono.morny.util.UseMath.**

View File

@ -1,6 +1,5 @@
package cc.sukazyo.cono.morny.extra package cc.sukazyo.cono.morny.social_share.external.bilibili
import cc.sukazyo.cono.morny.util.BiliTool
import cc.sukazyo.cono.morny.util.SttpPublic.{mornyBasicRequest, Schemes} import cc.sukazyo.cono.morny.util.SttpPublic.{mornyBasicRequest, Schemes}
import cc.sukazyo.cono.morny.util.UseSelect.select import cc.sukazyo.cono.morny.util.UseSelect.select
import sttp.client3.{HttpError, SttpClientException} import sttp.client3.{HttpError, SttpClientException}

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
import cc.sukazyo.cono.morny.util.SttpPublic import cc.sukazyo.cono.morny.util.SttpPublic
import cc.sukazyo.cono.morny.util.SttpPublic.mornyBasicRequest import cc.sukazyo.cono.morny.util.SttpPublic.mornyBasicRequest

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Information about the author of a tweet. /** Information about the author of a tweet.
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Data for external media, currently only video. /** Data for external media, currently only video.
* *

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
import cc.sukazyo.cono.morny.extra.twitter.FXMosaicPhoto.formatsType import cc.sukazyo.cono.morny.social_share.external.twitter.FXMosaicPhoto.formatsType
/** Data for the mosaic service, which stitches photos together /** Data for the mosaic service, which stitches photos together
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** This can help compare items in a pool of media /** This can help compare items in a pool of media
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Data for a poll on a given Tweet. /** Data for a poll on a given Tweet.
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Data for a single choice in a poll /** Data for a single choice in a poll
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Information about a requested translation for a Tweet, when asked. /** Information about a requested translation for a Tweet, when asked.
* *

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
import cc.sukazyo.cono.morny.extra.twitter.FXTweet.mediaType import cc.sukazyo.cono.morny.social_share.external.twitter.FXTweet.mediaType
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochSeconds import cc.sukazyo.cono.morny.util.EpochDateTime.EpochSeconds
/** The container of all the information for a Tweet. /** The container of all the information for a Tweet.

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.twitter package cc.sukazyo.cono.morny.social_share.external.twitter
/** Data for a Tweet's video /** Data for a Tweet's video
* *

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra package cc.sukazyo.cono.morny.social_share.external
import scala.util.matching.Regex import scala.util.matching.Regex

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.weibo package cc.sukazyo.cono.morny.social_share.external.weibo
case class MApi [D] ( case class MApi [D] (
ok: Int, ok: Int,

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.weibo package cc.sukazyo.cono.morny.social_share.external.weibo
case class MPic ( case class MPic (
pid: String, pid: String,

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.weibo package cc.sukazyo.cono.morny.social_share.external.weibo
case class MStatus ( case class MStatus (

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra.weibo package cc.sukazyo.cono.morny.social_share.external.weibo
case class MUser ( case class MUser (

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.extra package cc.sukazyo.cono.morny.social_share.external
package object weibo { package object weibo {

View File

@ -1,8 +1,9 @@
package cc.sukazyo.cono.morny.bot.query package cc.sukazyo.cono.morny.social_share.query
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.Log.{exceptionLog, logger}
import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, ITelegramQuery}
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update
import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode}
@ -24,7 +25,7 @@ class ShareToolBilibili (using coeur: MornyCoeur) extends ITelegramQuery {
if (event.inlineQuery.query == null) return null if (event.inlineQuery.query == null) return null
if (event.inlineQuery.query isBlank) return null if (event.inlineQuery.query isBlank) return null
import cc.sukazyo.cono.morny.extra.BilibiliForms.* import cc.sukazyo.cono.morny.social_share.external.bilibili.BilibiliForms.*
val result: BiliVideoId = val result: BiliVideoId =
try try
parse_videoUrl(event.inlineQuery.query) parse_videoUrl(event.inlineQuery.query)

View File

@ -1,8 +1,10 @@
package cc.sukazyo.cono.morny.bot.query package cc.sukazyo.cono.morny.social_share.query
import cc.sukazyo.cono.morny.data.social.{SocialTwitterParser, SocialWeiboParser}
import cc.sukazyo.cono.morny.extra.{twitter, weibo} import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, ITelegramQuery}
import cc.sukazyo.cono.morny.extra.twitter.{FXApi, TweetUrlInformation} import cc.sukazyo.cono.morny.social_share.api.{SocialTwitterParser, SocialWeiboParser}
import cc.sukazyo.cono.morny.extra.weibo.{MApi, StatusUrlInfo} import cc.sukazyo.cono.morny.social_share.external.{twitter, weibo}
import cc.sukazyo.cono.morny.social_share.external.twitter.{FXApi, TweetUrlInformation}
import cc.sukazyo.cono.morny.social_share.external.weibo.{MApi, StatusUrlInfo}
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update
class ShareToolSocialContent extends ITelegramQuery { class ShareToolSocialContent extends ITelegramQuery {

View File

@ -1,7 +1,8 @@
package cc.sukazyo.cono.morny.bot.query package cc.sukazyo.cono.morny.social_share.query
import cc.sukazyo.cono.morny.extra.twitter import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, ITelegramQuery}
import cc.sukazyo.cono.morny.extra.twitter.TweetUrlInformation import cc.sukazyo.cono.morny.social_share.external.twitter
import cc.sukazyo.cono.morny.social_share.external.twitter.TweetUrlInformation
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
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

View File

@ -1,11 +1,13 @@
package cc.sukazyo.cono.morny.bot.query package cc.sukazyo.cono.morny.tele_utils
import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, ITelegramQuery}
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
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}
import scala.language.postfixOps import scala.language.postfixOps
class RawText extends ITelegramQuery { class InlineRawText extends ITelegramQuery {
private val ID_PREFIX = "[morny/r/text]" private val ID_PREFIX = "[morny/r/text]"
private val TITLE = "Raw Text" private val TITLE = "Raw Text"

View File

@ -0,0 +1,45 @@
package cc.sukazyo.cono.morny.tele_utils
import cc.sukazyo.cono.morny.internal.MornyInternalModule
import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.tele_utils.event_hack.{CommandEventHack, EventHacker, HackerEventHandler}
import cc.sukazyo.cono.morny.tele_utils.user_info.{CommandGetUser, InlineMyInformation}
class ModuleTeleUtils extends MornyInternalModule {
override val id: String = "morny.tele_utils"
override val name: String = "Morny Tele Utils : EventHack, User data, and more"
override val description: String | Null =
// language=markdown
"""Added a serial tools for developing easier on Telegram.
|
|- `/event_hack`: Get the next event's raw serial data of you.
|- `/user`: Get user metadata for you or your roommate or by id.
| Also supported to get user's DC.
|""".stripMargin
override def onInitializingPre (using MornyCoeur)(cxt: MornyCoeur.OnInitializingPreContext): Unit = {
import cxt.*
given hacker: EventHacker = EventHacker()
externalContext << hacker
givenCxt << hacker
}
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.*
given EventHacker = externalContext >!> classOf[EventHacker]
eventManager register HackerEventHandler()
commandManager register CommandEventHack()
commandManager register CommandGetUser()
queryManager register InlineMyInformation()
queryManager register InlineRawText()
}
}

View File

@ -1,5 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.tele_utils.event_hack
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
@ -8,7 +10,7 @@ import com.pengrad.telegrambot.request.SendSticker
import scala.language.postfixOps import scala.language.postfixOps
class EventHack (using coeur: MornyCoeur) extends ITelegramCommand { class CommandEventHack (using hacker: EventHacker)(using coeur: MornyCoeur) extends ITelegramCommand {
override val name: String = "event_hack" override val name: String = "event_hack"
override val aliases: List[ICommandAlias] = Nil override val aliases: List[ICommandAlias] = Nil
@ -17,7 +19,7 @@ class EventHack (using coeur: MornyCoeur) extends ITelegramCommand {
override def execute (using command: InputCommand, event: Update): Unit = { override def execute (using command: InputCommand, event: Update): Unit = {
import coeur.daemons.eventHack.{registerHack, HackType} import hacker.{registerHack, HackType}
val x_mode = if (command.args nonEmpty) command.args(0) else "" val x_mode = if (command.args nonEmpty) command.args(0) else ""

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.daemon package cc.sukazyo.cono.morny.tele_utils.event_hack
import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.Log.logger
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur

View File

@ -1,4 +1,4 @@
package cc.sukazyo.cono.morny.bot.event package cc.sukazyo.cono.morny.tele_utils.event_hack
import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener} import cc.sukazyo.cono.morny.bot.api.{EventEnv, EventListener}
import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.Log.logger
@ -11,11 +11,11 @@ import com.pengrad.telegrambot.request.SendMessage
import scala.collection.mutable import scala.collection.mutable
import scala.language.postfixOps import scala.language.postfixOps
class OnEventHackHandle (using coeur: MornyCoeur) extends EventListener { class HackerEventHandler (using hacker: EventHacker)(using coeur: MornyCoeur) extends EventListener {
private def trigger (chat_id: Long, from_id: Long)(using event: EventEnv): Unit = private def trigger (chat_id: Long, from_id: Long)(using event: EventEnv): Unit =
given Update = event.update given Update = event.update
if coeur.daemons.eventHack.trigger(chat_id, from_id) then if hacker.trigger(chat_id, from_id) then
event.setEventOk event.setEventOk
override def onMessage (using event: EventEnv): Unit = override def onMessage (using event: EventEnv): Unit =

View File

@ -1,6 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.tele_utils.user_info
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ITelegramCommand}
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 cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
@ -10,7 +11,7 @@ import com.pengrad.telegrambot.request.{GetChatMember, SendMessage}
import scala.language.postfixOps import scala.language.postfixOps
class GetUsernameAndId (using coeur: MornyCoeur) extends ITelegramCommand { class CommandGetUser (using coeur: MornyCoeur) extends ITelegramCommand {
override val name: String = "user" override val name: String = "user"
override val aliases: List[ICommandAlias] = Nil override val aliases: List[ICommandAlias] = Nil

View File

@ -1,5 +1,6 @@
package cc.sukazyo.cono.morny.bot.query package cc.sukazyo.cono.morny.tele_utils.user_info
import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, ITelegramQuery}
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
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
@ -7,7 +8,7 @@ import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTex
import scala.language.postfixOps import scala.language.postfixOps
class MyInformation extends ITelegramQuery { class InlineMyInformation extends ITelegramQuery {
private val ID_PREFIX = "[morny/info/me]" private val ID_PREFIX = "[morny/info/me]"
private val TITLE = "My Account Information" private val TITLE = "My Account Information"

View File

@ -1,12 +1,12 @@
package cc.sukazyo.cono.morny.uni_meow package cc.sukazyo.cono.morny.uni_meow
import cc.sukazyo.cono.morny.{MornyCoeur, MornyModule, MornySystem} import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.internal.MornyInternalModule
class ModuleUniMeow extends MornyModule { class ModuleUniMeow extends MornyInternalModule {
override val id: String = "coeur.uni_meow" override val id: String = "coeur.uni_meow"
override val name: String = "Coeur Uni-Meow Commands" override val name: String = "Coeur Uni-Meow Commands"
override val version: String = MornySystem.VERSION
override val description: String | Null = override val description: String | Null =
// language=Markdown // language=Markdown
"""Provides support for unicode command in Telegram. Also provided some """Provides support for unicode command in Telegram. Also provided some
@ -16,11 +16,15 @@ class ModuleUniMeow extends MornyModule {
val uni_commands: UniMeowCommandManager = UniMeowCommandManager() val uni_commands: UniMeowCommandManager = UniMeowCommandManager()
override def onInitializingPre (using MornyCoeur)(cxt: MornyCoeur.OnInitializingPreContext): Unit = {
import cxt.*
externalContext << uni_commands
givenCxt << uni_commands
}
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = { override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
import cxt.* import cxt.*
externalContext << uni_commands
givenCxt << uni_commands
eventManager.register( eventManager.register(
BotEventUniMeowTrigger(using uni_commands) BotEventUniMeowTrigger(using uni_commands)
) )
@ -37,7 +41,8 @@ class ModuleUniMeow extends MornyModule {
//noinspection NonAsciiCharacters //noinspection NonAsciiCharacters
commandManager.register( commandManager.register(
$喵呜.Progynova, $喵呜.Progynova,
私わね() 私わね(),
().Chuang
) )
} }

View File

@ -1,6 +1,7 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.uni_meow
import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.MornyCoeur
import cc.sukazyo.cono.morny.bot.command.{ICommandAlias, ISimpleCommand}
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.* import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.*
import com.pengrad.telegrambot.model.{MessageEntity, Update} import com.pengrad.telegrambot.model.{MessageEntity, Update}

View File

@ -1,13 +1,33 @@
package cc.sukazyo.cono.morny.util package cc.sukazyo.cono.morny.util
import cc.sukazyo.cono.morny.util.GivenContext.ContextNotGivenException import cc.sukazyo.cono.morny.util.GivenContext.{ContextNotGivenException, FolderClass, RequestItemClass}
import cc.sukazyo.messiva.utils.StackUtils
import scala.annotation.targetName import scala.annotation.targetName
import scala.collection.mutable import scala.collection.mutable
import scala.reflect.{classTag, ClassTag} import scala.reflect.{classTag, ClassTag}
import scala.util.boundary
object GivenContext { object GivenContext {
class ContextNotGivenException extends NoSuchElementException case class FolderClass (clazz: Option[Class[?]])
object FolderClass:
def default: FolderClass = FolderClass(None)
case class RequestItemClass (clazz: Class[?])
private def lastNonGCStack: StackTraceElement =
boundary {
for (stack <- StackUtils.getStackTrace(0)) {
if (!stack.getClassName.startsWith(classOf[GivenContext].getName))
boundary break stack
}
StackTraceElement("unknown", "unknown", "unknown", -1)
}
class ContextNotGivenException (using
val requestItemClass: RequestItemClass,
val folderClass: FolderClass = FolderClass.default,
val requestStack: StackTraceElement = UseStacks.getStackHeadBeforeClass[GivenContext]
) extends NoSuchElementException (
s"None of the ${requestItemClass.clazz.getSimpleName} is in the context${folderClass.clazz.map(" and owned by " + _.getSimpleName).getOrElse("")}, which is required by $requestStack."
)
} }
/** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type. /** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type.
@ -67,7 +87,8 @@ class GivenContext {
private type CxtOption[T] = Either[ContextNotGivenException, T] private type CxtOption[T] = Either[ContextNotGivenException, T]
def use [T: ClassTag]: CxtOption[T] = def use [T: ClassTag]: CxtOption[T] =
variables get classTag[T].runtimeClass match given t: RequestItemClass = RequestItemClass(classTag[T].runtimeClass)
variables get t.clazz match
case Some(i) => Right(i.asInstanceOf[T]) case Some(i) => Right(i.asInstanceOf[T])
case None => Left(ContextNotGivenException()) case None => Left(ContextNotGivenException())
def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
@ -101,9 +122,13 @@ class GivenContext {
this.provide[T](i) this.provide[T](i)
def use [T: ClassTag]: CxtOption[T] = def use [T: ClassTag]: CxtOption[T] =
variablesWithOwner(classTag[O].runtimeClass) get classTag[T].runtimeClass match given t: RequestItemClass = RequestItemClass(classTag[T].runtimeClass)
given u: FolderClass = FolderClass(Some(classTag[O].runtimeClass))
variablesWithOwner get u.clazz.get match
case Some(varColl) => varColl get t.clazz match
case Some(i) => Right(i.asInstanceOf[T]) case Some(i) => Right(i.asInstanceOf[T])
case None => Left(ContextNotGivenException()) case None => Left(ContextNotGivenException())
case None => Left(ContextNotGivenException())
def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] = def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
use[T] match use[T] match
case Left(_) => ConsumeFailed[U]() case Left(_) => ConsumeFailed[U]()

View File

@ -0,0 +1,20 @@
package cc.sukazyo.cono.morny.util
import cc.sukazyo.messiva.utils.StackUtils
import scala.reflect.{classTag, ClassTag}
import scala.util.boundary
object UseStacks {
def getStackHeadBeforeClass[T: ClassTag]: StackTraceElement = {
boundary {
for (stack <- StackUtils.getStackTrace(1)) {
if (!stack.getClassName.startsWith(classTag[T].runtimeClass.getName))
boundary break stack
}
StackTraceElement("unknown", "unknown", "unknown", -1)
}
}
}

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.test.bot.event package cc.sukazyo.cono.morny.test.bot.event
import cc.sukazyo.cono.morny.bot.event.OnQuestionMarkReply import cc.sukazyo.cono.morny.randomize_somthing.OnQuestionMarkReply
import cc.sukazyo.cono.morny.test.MornyTests import cc.sukazyo.cono.morny.test.MornyTests
import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.prop.TableDrivenPropertyChecks

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.test.daemon package cc.sukazyo.cono.morny.test.daemon
import cc.sukazyo.cono.morny.daemon.MedicationTimer import cc.sukazyo.cono.morny.medication_timer.MedicationTimer
import cc.sukazyo.cono.morny.test.MornyTests import cc.sukazyo.cono.morny.test.MornyTests
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis
import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.prop.TableDrivenPropertyChecks

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.test.extra package cc.sukazyo.cono.morny.test.extra
import cc.sukazyo.cono.morny.extra.BilibiliForms.* import cc.sukazyo.cono.morny.social_share.external.bilibili.BilibiliForms.*
import cc.sukazyo.cono.morny.test.MornyTests import cc.sukazyo.cono.morny.test.MornyTests
import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.prop.TableDrivenPropertyChecks

View File

@ -1,7 +1,7 @@
package cc.sukazyo.cono.morny.test.extra.twitter package cc.sukazyo.cono.morny.test.extra.twitter
import cc.sukazyo.cono.morny.extra.twitter.FXApi import cc.sukazyo.cono.morny.social_share.external.twitter.FXApi
import cc.sukazyo.cono.morny.extra.twitter.FXApi.Fetch import cc.sukazyo.cono.morny.social_share.external.twitter.FXApi.Fetch
import cc.sukazyo.cono.morny.test.MornyTests import cc.sukazyo.cono.morny.test.MornyTests
import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.tagobjects.{Network, Slow} import org.scalatest.tagobjects.{Network, Slow}

View File

@ -1,6 +1,6 @@
package cc.sukazyo.cono.morny.test.extra.twitter package cc.sukazyo.cono.morny.test.extra.twitter
import cc.sukazyo.cono.morny.extra.twitter.{parseTweetUrl, TweetUrlInformation} import cc.sukazyo.cono.morny.social_share.external.twitter.{parseTweetUrl, TweetUrlInformation}
import cc.sukazyo.cono.morny.test.MornyTests import cc.sukazyo.cono.morny.test.MornyTests
class PackageTest extends MornyTests { class PackageTest extends MornyTests {

View File

@ -16,13 +16,13 @@ class BiliToolTest extends MornyTests with TableDrivenPropertyChecks {
) )
forAll (examples) { (bv, av) => s"while using av$av/BV$bv :" - { forAll (examples) { (bv, av) => s"while using av$av/BV$bv :" - {
import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} import cc.sukazyo.cono.morny.social_share.external.bilibili.BiliTool.{toAv, toBv}
"av to bv works" in { toBv(av) shouldEqual bv } "av to bv works" in { toBv(av) shouldEqual bv }
"bv to av works" in { toAv(bv) shouldEqual av } "bv to av works" in { toAv(bv) shouldEqual av }
}} }}
"BV with unsupported length :" - { "BV with unsupported length :" - {
import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} import cc.sukazyo.cono.morny.social_share.external.bilibili.BiliTool.{toAv, IllegalFormatException}
val examples = Table( val examples = Table(
"bv", "bv",
"12345", "12345",
@ -48,7 +48,7 @@ class BiliToolTest extends MornyTests with TableDrivenPropertyChecks {
("1mK4O1C7Bl", "l"), ("1mK4O1C7Bl", "l"),
("1--4O1C7Bl", "[symbols]") ("1--4O1C7Bl", "[symbols]")
) )
import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} import cc.sukazyo.cono.morny.social_share.external.bilibili.BiliTool.{toAv, IllegalFormatException}
forAll(examples) { (bv, with_sp) => forAll(examples) { (bv, with_sp) =>
s"'$with_sp' should throws IllegalFormatException" in: s"'$with_sp' should throws IllegalFormatException" in:
an [IllegalFormatException] should be thrownBy toAv(bv) an [IllegalFormatException] should be thrownBy toAv(bv)
@ -58,7 +58,7 @@ class BiliToolTest extends MornyTests with TableDrivenPropertyChecks {
"av/bv converting should be reversible" in { "av/bv converting should be reversible" in {
for (_ <- 1 to 20) { for (_ <- 1 to 20) {
val rand_av = Random.between(0, 999999999L) val rand_av = Random.between(0, 999999999L)
import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} import cc.sukazyo.cono.morny.social_share.external.bilibili.BiliTool.{toAv, toBv}
val my_bv = toBv(rand_av) val my_bv = toBv(rand_av)
toAv(my_bv) shouldEqual rand_av toAv(my_bv) shouldEqual rand_av
toBv(toAv(my_bv)) shouldEqual my_bv toBv(toAv(my_bv)) shouldEqual my_bv