mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-23 03:27:39 +08:00
Compare commits
4 Commits
bfacb0d039
...
985fde9aa2
Author | SHA1 | Date | |
---|---|---|---|
985fde9aa2 | |||
981098cf6e | |||
69086b1f36 | |||
1bd795873c |
16
README.md
16
README.md
@ -4,19 +4,22 @@
|
|||||||
[todo]: https://github.com/users/Eyre-S/projects/1
|
[todo]: https://github.com/users/Eyre-S/projects/1
|
||||||
[artifact]: https://mvn.sukazyo.cc/#/releases/cc/sukazyo/morny-coeur
|
[artifact]: https://mvn.sukazyo.cc/#/releases/cc/sukazyo/morny-coeur
|
||||||
|
|
||||||
[tg4j]: https://github.com/pengrad/java-telegram-bot-api
|
[scala]: https://www.scala-lang.org/
|
||||||
[spotbugs]: https://spotbugs.github.io/
|
[spotbugs]: https://spotbugs.github.io/
|
||||||
[junit5]: https://junit.org/junit5/
|
[tg4j]: https://github.com/pengrad/java-telegram-bot-api
|
||||||
|
[okhttp]: https://square.github.io/okhttp/
|
||||||
|
[gson]: https://github.com/google/gson
|
||||||
|
[scalatest]: https://scalatest.org/
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
|
|
||||||
# ~~给所有喜欢morny的大家的~~ Morny Coeur 源代码
|
# ~~给所有喜欢morny的大家的~~ Morny Coeur 源代码
|
||||||
|
|
||||||
~~"你们又有意见又不发issue这样子我很为难的啊"~~
|
~~"and nobody cares."~~
|
||||||
|
|
||||||
![social preview card](morny-github-social-preview-card@0.75x.png)
|
![social preview card](morny-github-social-preview-card@0.75x.png)
|
||||||
|
|
||||||
一个 telegram 上的服侍 A.C.Sukazyo Eyre 和它的花宫成员的 bot 的内核源
|
一个 telegram 上的服侍 A.C.Sukazyo Eyre 和它的花宫成员的 bot 内核
|
||||||
|
|
||||||
[Task Listing][todo] | [~~BBS~~][issues] | [Published][artifact]
|
[Task Listing][todo] | [~~BBS~~][issues] | [Published][artifact]
|
||||||
|
|
||||||
@ -32,6 +35,9 @@
|
|||||||
|
|
||||||
[Java Telegram Bot API][tg4j]
|
[Java Telegram Bot API][tg4j]
|
||||||
|
|
||||||
[SpotBugs Annotations][spotbugs] | [JUnit 5][junit5]
|
|
||||||
|
[okhttp] | [Gson][gson]
|
||||||
|
|
||||||
|
[Scala][scala] | [SpotBugs Annotations][spotbugs] | [ScalaTest][scalatest]
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -92,6 +92,10 @@ dependencies {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
|
||||||
sourceCompatibility proj_java.getMajorVersion()
|
sourceCompatibility proj_java.getMajorVersion()
|
||||||
@ -144,9 +148,12 @@ buildConfig {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Jar).configureEach {
|
||||||
|
archiveBaseName.set proj_archive_name
|
||||||
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
|
|
||||||
archiveBaseName.set proj_archive_name
|
|
||||||
archiveClassifier.set "fat"
|
archiveClassifier.set "fat"
|
||||||
|
|
||||||
if (project.hasProperty("dockerBuild")) {
|
if (project.hasProperty("dockerBuild")) {
|
||||||
|
@ -7,8 +7,8 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s
|
|||||||
|
|
||||||
VERSION = 1.0.0-RC5
|
VERSION = 1.0.0-RC5
|
||||||
|
|
||||||
USE_DELTA = true
|
USE_DELTA = false
|
||||||
VERSION_DELTA = scala3
|
VERSION_DELTA =
|
||||||
|
|
||||||
CODENAME = beiping
|
CODENAME = beiping
|
||||||
|
|
||||||
|
@ -31,10 +31,12 @@ class MornyCoeur (using val config: MornyConfig) {
|
|||||||
if config.telegramBotUsername ne null then
|
if config.telegramBotUsername ne null then
|
||||||
logger info s"login as:\n ${config.telegramBotUsername}"
|
logger info s"login as:\n ${config.telegramBotUsername}"
|
||||||
|
|
||||||
private val __loginResult = login()
|
private val __loginResult: LoginResult = login() match
|
||||||
if (__loginResult eq null)
|
case some: Some[LoginResult] => some.get
|
||||||
|
case None =>
|
||||||
logger error "Login to bot failed."
|
logger error "Login to bot failed."
|
||||||
System exit -1
|
System exit -1
|
||||||
|
throw RuntimeException()
|
||||||
|
|
||||||
configure_exitCleanup()
|
configure_exitCleanup()
|
||||||
|
|
||||||
@ -63,8 +65,8 @@ class MornyCoeur (using val config: MornyConfig) {
|
|||||||
val events: MornyEventListeners = MornyEventListeners(using eventManager)
|
val events: MornyEventListeners = MornyEventListeners(using eventManager)
|
||||||
|
|
||||||
/** inner value: about why morny exit, used in [[daemon.MornyReport]]. */
|
/** inner value: about why morny exit, used in [[daemon.MornyReport]]. */
|
||||||
private var whileExit_reason: AnyRef|Null = _
|
private var whileExit_reason: Option[AnyRef] = None
|
||||||
def exitReason: AnyRef|Null = whileExit_reason
|
def exitReason: Option[AnyRef] = whileExit_reason
|
||||||
val coeurStartTimestamp: Long = ServerMain.systemStartupTime
|
val coeurStartTimestamp: Long = ServerMain.systemStartupTime
|
||||||
|
|
||||||
///>>> BLOCK START instance configure & startup stage 2
|
///>>> BLOCK START instance configure & startup stage 2
|
||||||
@ -101,12 +103,12 @@ class MornyCoeur (using val config: MornyConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def exit (status: Int, reason: AnyRef): Unit =
|
def exit (status: Int, reason: AnyRef): Unit =
|
||||||
whileExit_reason = reason
|
whileExit_reason = Some(reason)
|
||||||
System exit status
|
System exit status
|
||||||
|
|
||||||
private case class LoginResult(account: TelegramBot, username: String, userid: Long)
|
private case class LoginResult(account: TelegramBot, username: String, userid: Long)
|
||||||
|
|
||||||
private def login (): LoginResult|Null = {
|
private def login (): Option[LoginResult] = {
|
||||||
|
|
||||||
val builder = TelegramBot.Builder(config.telegramBotKey)
|
val builder = TelegramBot.Builder(config.telegramBotKey)
|
||||||
var api_bot = config.telegramBotApiServer
|
var api_bot = config.telegramBotApiServer
|
||||||
@ -129,7 +131,7 @@ class MornyCoeur (using val config: MornyConfig) {
|
|||||||
val account = builder build
|
val account = builder build
|
||||||
|
|
||||||
logger info "Trying to login..."
|
logger info "Trying to login..."
|
||||||
boundary[LoginResult|Null] {
|
boundary[Option[LoginResult]] {
|
||||||
for (i <- 0 to 3) {
|
for (i <- 0 to 3) {
|
||||||
if i > 0 then logger info "retrying..."
|
if i > 0 then logger info "retrying..."
|
||||||
try {
|
try {
|
||||||
@ -137,16 +139,16 @@ class MornyCoeur (using val config: MornyConfig) {
|
|||||||
if ((config.telegramBotUsername ne null) && config.telegramBotUsername != remote.username)
|
if ((config.telegramBotUsername ne null) && config.telegramBotUsername != remote.username)
|
||||||
throw RuntimeException(s"Required the bot @${config.telegramBotUsername} but @${remote.username} logged in")
|
throw RuntimeException(s"Required the bot @${config.telegramBotUsername} but @${remote.username} logged in")
|
||||||
logger info s"Succeed logged in to @${remote.username}"
|
logger info s"Succeed logged in to @${remote.username}"
|
||||||
break(LoginResult(account, remote.username, remote.id))
|
break(Some(LoginResult(account, remote.username, remote.id)))
|
||||||
} catch
|
} catch
|
||||||
case r: boundary.Break[LoginResult|Null] => throw r
|
case r: boundary.Break[Option[LoginResult]] => throw r
|
||||||
case e =>
|
case e =>
|
||||||
logger error
|
logger error
|
||||||
s"""${exceptionLog(e)}
|
s"""${exceptionLog(e)}
|
||||||
|login failed"""
|
|login failed"""
|
||||||
.stripMargin
|
.stripMargin
|
||||||
}
|
}
|
||||||
null
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,12 @@ import com.pengrad.telegrambot.UpdatesListener
|
|||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.language.postfixOps
|
import scala.language.postfixOps
|
||||||
|
|
||||||
|
/** Contains a [[mutable.Queue]] of [[EventListener]], and delivery telegram [[Update]].
|
||||||
|
*
|
||||||
|
* Implemented [[process]] in [[UpdatesListener]] so it can directly used in [[com.pengrad.telegrambot.TelegramBot.setupListener]].
|
||||||
|
*
|
||||||
|
* @param coeur the [[MornyCoeur]] context.
|
||||||
|
*/
|
||||||
class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener {
|
class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener {
|
||||||
|
|
||||||
private val listeners = mutable.Queue.empty[EventListener]
|
private val listeners = mutable.Queue.empty[EventListener]
|
||||||
@ -77,9 +83,19 @@ class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
import java.util
|
import java.util
|
||||||
import scala.jdk.CollectionConverters.*
|
import scala.jdk.CollectionConverters.*
|
||||||
|
/** Delivery the telegram [[Update]]s.
|
||||||
|
*
|
||||||
|
* The implementation of [[UpdatesListener]].
|
||||||
|
*
|
||||||
|
* For each [[Update]], create an [[EventRunner]] for it, and
|
||||||
|
* start the it.
|
||||||
|
*
|
||||||
|
* @return [[UpdatesListener.CONFIRMED_UPDATES_ALL]], for all Updates
|
||||||
|
* should be processed in [[EventRunner]] created for it.
|
||||||
|
*/
|
||||||
override def process (updates: util.List[Update]): Int = {
|
override def process (updates: util.List[Update]): Int = {
|
||||||
for (update <- updates.asScala)
|
for (update <- updates.asScala)
|
||||||
EventRunner(using update).start()
|
EventRunner(using update).start()
|
||||||
|
@ -1,17 +1,43 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
/** One alias definition, contains the necessary message of how
|
||||||
|
* to process the alias.
|
||||||
|
*/
|
||||||
trait ICommandAlias {
|
trait ICommandAlias {
|
||||||
|
|
||||||
|
/** The alias name.
|
||||||
|
*
|
||||||
|
* same with the command name, it is the unique identifier of this alias.
|
||||||
|
*/
|
||||||
val name: String
|
val name: String
|
||||||
|
/** If the alias should be listed while list commands to end-user.
|
||||||
|
*
|
||||||
|
* The alias can only be listed when the parent command can be listed
|
||||||
|
* (meanwhile the parent command implemented [[ITelegramCommand]]). If the
|
||||||
|
* parent command cannot be listed, it will always cannot be listed.
|
||||||
|
*/
|
||||||
val listed: Boolean
|
val listed: Boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Default implementations of [[ICommandAlias]]. */
|
||||||
object ICommandAlias {
|
object ICommandAlias {
|
||||||
|
|
||||||
|
/** Alias which can be listed to end-user.
|
||||||
|
*
|
||||||
|
* the [[ICommandAlias.listed]] value is always true.
|
||||||
|
*
|
||||||
|
* @param name The alias name, see more in [[ICommandAlias.name]]
|
||||||
|
*/
|
||||||
case class ListedAlias (name: String) extends ICommandAlias:
|
case class ListedAlias (name: String) extends ICommandAlias:
|
||||||
override val listed = true
|
override val listed = true
|
||||||
|
|
||||||
|
/** Alias which cannot be listed to end-user.
|
||||||
|
*
|
||||||
|
* the [[ICommandAlias.listed]] value is always false.
|
||||||
|
*
|
||||||
|
* @param name The alias name, see more in [[ICommandAlias.name]]
|
||||||
|
*/
|
||||||
case class HiddenAlias (name: String) extends ICommandAlias:
|
case class HiddenAlias (name: String) extends ICommandAlias:
|
||||||
override val listed = false
|
override val listed = false
|
||||||
|
|
||||||
|
@ -3,11 +3,37 @@ package cc.sukazyo.cono.morny.bot.command
|
|||||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
import com.pengrad.telegrambot.model.Update
|
import com.pengrad.telegrambot.model.Update
|
||||||
|
|
||||||
|
/** A simple command.
|
||||||
|
*
|
||||||
|
* Contains only [[name]] and [[aliases]].
|
||||||
|
*
|
||||||
|
* Won't be listed to end-user. if you want the command listed,
|
||||||
|
* see [[ITelegramCommand]].
|
||||||
|
*
|
||||||
|
*/
|
||||||
trait ISimpleCommand {
|
trait ISimpleCommand {
|
||||||
|
|
||||||
|
/** the main name of the command.
|
||||||
|
*
|
||||||
|
* must have a value as the unique identifier of this command.
|
||||||
|
*/
|
||||||
val name: String
|
val name: String
|
||||||
|
/** aliases of the command.
|
||||||
|
*
|
||||||
|
* Alias means it is the same to call [[name main name]] when call this.
|
||||||
|
* There can be multiple aliases. But notice that, although alias is not
|
||||||
|
* the unique identifier, it uses the same namespace with [[name]], means
|
||||||
|
* it also cannot be duplicate with other [[name]] or [[aliases]].
|
||||||
|
*
|
||||||
|
* It can be [[Null]], means no aliases.
|
||||||
|
*/
|
||||||
val aliases: Array[ICommandAlias]|Null
|
val aliases: Array[ICommandAlias]|Null
|
||||||
|
|
||||||
|
/** The work code of this command.
|
||||||
|
*
|
||||||
|
* @param command The parsed input command which called this command.
|
||||||
|
* @param event The raw event which called this command.
|
||||||
|
*/
|
||||||
def execute (using command: InputCommand, event: Update): Unit
|
def execute (using command: InputCommand, event: Update): Unit
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,25 @@
|
|||||||
package cc.sukazyo.cono.morny.bot.command
|
package cc.sukazyo.cono.morny.bot.command
|
||||||
|
|
||||||
|
/** A complex telegram command.
|
||||||
|
*
|
||||||
|
* the extension of [[ISimpleCommand]], with external defines of the necessary
|
||||||
|
* introduction message ([[paramRule]] and [[description]]).
|
||||||
|
*
|
||||||
|
* It can be listed to end-user.
|
||||||
|
*/
|
||||||
trait ITelegramCommand extends ISimpleCommand {
|
trait ITelegramCommand extends ISimpleCommand {
|
||||||
|
|
||||||
|
/** The param rule of this command, used in human-readable command list.
|
||||||
|
*
|
||||||
|
* The param rule uses a symbol language to describe how this command
|
||||||
|
* receives paras.
|
||||||
|
*
|
||||||
|
* Set it empty to make this scope not available.
|
||||||
|
*/
|
||||||
val paramRule: String
|
val paramRule: String
|
||||||
|
/** The description/introduction of this command, used in human-readable
|
||||||
|
* command list.
|
||||||
|
*/
|
||||||
val description: String
|
val description: String
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ class MornyInformation (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
/* language=html */
|
/* language=html */
|
||||||
s"""system:
|
s"""system:
|
||||||
|- <code>${h(if (getRuntimeHostname == null) "<unknown-host>" else getRuntimeHostname)}</code>
|
|- <code>${h(if getRuntimeHostname nonEmpty then getRuntimeHostname.get else "<unknown-host>")}</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>
|
||||||
|java runtime:
|
|java runtime:
|
||||||
|- <code>${h(sysprop("java.vm.vendor"))}.${h(sysprop("java.vm.name"))}</code>
|
|- <code>${h(sysprop("java.vm.vendor"))}.${h(sysprop("java.vm.name"))}</code>
|
||||||
|
@ -25,14 +25,12 @@ class Nbnhhsh (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
|
|
||||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
|
||||||
val queryTarget: String|Null =
|
val queryTarget: String =
|
||||||
if command.args nonEmpty then
|
if command.args nonEmpty then
|
||||||
command.args mkString " "
|
command.args mkString " "
|
||||||
else if (event.message.replyToMessage != null && event.message.replyToMessage.text != null)
|
else if (event.message.replyToMessage != null && event.message.replyToMessage.text != null)
|
||||||
event.message.replyToMessage.text
|
event.message.replyToMessage.text
|
||||||
else null
|
else
|
||||||
|
|
||||||
if (queryTarget == null)
|
|
||||||
coeur.account exec SendSticker(
|
coeur.account exec SendSticker(
|
||||||
event.message.chat.id,
|
event.message.chat.id,
|
||||||
TelegramStickers ID_404
|
TelegramStickers ID_404
|
||||||
|
@ -129,8 +129,8 @@ class OnCallMsgSend (using coeur: MornyCoeur) extends EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if messageToSend.message eq null then return true
|
if messageToSend.message eq null then return true
|
||||||
val testSendResponse = coeur.account execute messageToSend.toSendMessage(update.message.chat.id)
|
val testSendResponse = coeur.account execute
|
||||||
.replyToMessageId(update.message.messageId)
|
messageToSend.toSendMessage(update.message.chat.id).replyToMessageId(update.message.messageId)
|
||||||
if (!(testSendResponse isOk))
|
if (!(testSendResponse isOk))
|
||||||
coeur.account exec SendMessage(
|
coeur.account exec SendMessage(
|
||||||
update.message.chat.id,
|
update.message.chat.id,
|
||||||
|
@ -8,6 +8,7 @@ import com.pengrad.telegrambot.model.Update
|
|||||||
import com.pengrad.telegrambot.request.SendMessage
|
import com.pengrad.telegrambot.request.SendMessage
|
||||||
|
|
||||||
import scala.language.postfixOps
|
import scala.language.postfixOps
|
||||||
|
import scala.util.boundary
|
||||||
|
|
||||||
class OnQuestionMarkReply (using coeur: MornyCoeur) extends EventListener {
|
class OnQuestionMarkReply (using coeur: MornyCoeur) extends EventListener {
|
||||||
|
|
||||||
@ -34,10 +35,10 @@ object OnQuestionMarkReply {
|
|||||||
private val QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓')
|
private val QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓')
|
||||||
|
|
||||||
def isAllMessageMark (using text: String): Boolean = {
|
def isAllMessageMark (using text: String): Boolean = {
|
||||||
var isAll = true
|
boundary[Boolean] {
|
||||||
for (c <- text)
|
for (c <- text) if QUESTION_MARKS contains c then boundary.break(false)
|
||||||
if !(QUESTION_MARKS contains c) then isAll = false
|
true
|
||||||
isAll
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ 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.util.tgapi.formatting.NamingUtils.inlineQueryId
|
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
|
||||||
import cc.sukazyo.cono.morny.util.BiliTool
|
import cc.sukazyo.cono.morny.util.BiliTool
|
||||||
|
import cc.sukazyo.cono.morny.util.UseSelect.select
|
||||||
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,23 +25,23 @@ class ShareToolBilibili extends ITelegramQuery {
|
|||||||
if (event.inlineQuery.query == null) return null
|
if (event.inlineQuery.query == null) return null
|
||||||
|
|
||||||
event.inlineQuery.query match
|
event.inlineQuery.query match
|
||||||
case REGEX_BILI_VIDEO(_1, _2, _3, _4, _5, _6, _7) =>
|
case REGEX_BILI_VIDEO(_url_v, _url_av, _url_bv, _url_param, _url_v_part, _raw_av, _raw_bv) =>
|
||||||
|
|
||||||
logger debug
|
logger debug
|
||||||
s"""====== Share Tool Bilibili Catch ok
|
s"""====== Share Tool Bilibili Catch ok
|
||||||
|1: ${_1}
|
|1: ${_url_v}
|
||||||
|2: ${_2}
|
|2: ${_url_av}
|
||||||
|3: ${_3}
|
|3: ${_url_bv}
|
||||||
|4: ${_4}
|
|4: ${_url_param}
|
||||||
|5: ${_5}
|
|5: ${_url_v_part}
|
||||||
|6: ${_6}
|
|6: ${_raw_av}
|
||||||
|7: ${_7}"""
|
|7: ${_raw_bv}"""
|
||||||
.stripMargin
|
.stripMargin
|
||||||
|
|
||||||
var av = if (_2 != null) _2 else if (_6 != null) _6 else null
|
var av = select(_url_av, _raw_av)
|
||||||
var bv = if (_3!=null) _3 else if (_7!=null) _7 else null
|
var bv = select(_url_bv, _raw_bv)
|
||||||
logger trace s"catch id av[$av] bv[$bv]"
|
logger trace s"catch id av[$av] bv[$bv]"
|
||||||
val part: Int|Null = if (_5!=null) _5 toInt else null
|
val part: Int|Null = if (_url_v_part!=null) _url_v_part toInt else null
|
||||||
logger trace s"catch video part[$part]"
|
logger trace s"catch video part[$part]"
|
||||||
|
|
||||||
if (av == null) {
|
if (av == null) {
|
||||||
|
@ -21,15 +21,15 @@ class ShareToolTwitter extends ITelegramQuery {
|
|||||||
|
|
||||||
event.inlineQuery.query match
|
event.inlineQuery.query match
|
||||||
|
|
||||||
case REGEX_TWEET_LINK(_, _2, _, _, _, _) =>
|
case REGEX_TWEET_LINK(_, _path_data, _, _, _, _) =>
|
||||||
List(
|
List(
|
||||||
InlineQueryUnit(InlineQueryResultArticle(
|
InlineQueryUnit(InlineQueryResultArticle(
|
||||||
inlineQueryId(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX,
|
inlineQueryId(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX,
|
||||||
s"https://vxtwitter.com/$_2"
|
s"https://vxtwitter.com/$_path_data"
|
||||||
)),
|
)),
|
||||||
InlineQueryUnit(InlineQueryResultArticle(
|
InlineQueryUnit(InlineQueryResultArticle(
|
||||||
inlineQueryId(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED,
|
inlineQueryId(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED,
|
||||||
s"https://c.vxtwitter.com/$_2"
|
s"https://c.vxtwitter.com/$_path_data"
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
|||||||
|
|
||||||
this.setName(DAEMON_THREAD_NAME_DEF)
|
this.setName(DAEMON_THREAD_NAME_DEF)
|
||||||
|
|
||||||
private var lastNotify_messageId: Int|Null = _
|
private var lastNotify_messageId: Option[Int] = None
|
||||||
|
|
||||||
override def run (): Unit = {
|
override def run (): Unit = {
|
||||||
logger info "Medication Timer started."
|
logger info "Medication Timer started."
|
||||||
@ -51,8 +51,8 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
|||||||
|
|
||||||
private def sendNotification(): Unit = {
|
private def sendNotification(): Unit = {
|
||||||
val sendResponse: SendResponse = coeur.account exec SendMessage(notify_toChat, NOTIFY_MESSAGE)
|
val sendResponse: SendResponse = coeur.account exec SendMessage(notify_toChat, NOTIFY_MESSAGE)
|
||||||
if sendResponse isOk then lastNotify_messageId = sendResponse.message.messageId
|
if sendResponse isOk then lastNotify_messageId = Some(sendResponse.message.messageId)
|
||||||
else lastNotify_messageId = null
|
else lastNotify_messageId = None
|
||||||
}
|
}
|
||||||
|
|
||||||
@throws[InterruptedException | IllegalArgumentException]
|
@throws[InterruptedException | IllegalArgumentException]
|
||||||
@ -61,7 +61,7 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def refreshNotificationWrite (edited: Message): Unit = {
|
def refreshNotificationWrite (edited: Message): Unit = {
|
||||||
if lastNotify_messageId != (edited.messageId toInt) then return
|
if (lastNotify_messageId isEmpty) || (lastNotify_messageId.get != (edited.messageId toInt)) then return
|
||||||
import cc.sukazyo.cono.morny.util.CommonFormat.formatDate
|
import cc.sukazyo.cono.morny.util.CommonFormat.formatDate
|
||||||
val editTime = formatDate(edited.editDate*1000, use_timeZone.getTotalSeconds/60/60)
|
val editTime = formatDate(edited.editDate*1000, use_timeZone.getTotalSeconds/60/60)
|
||||||
val entities = ArrayBuffer.empty[MessageEntity]
|
val entities = ArrayBuffer.empty[MessageEntity]
|
||||||
@ -72,7 +72,7 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
|||||||
edited.messageId,
|
edited.messageId,
|
||||||
edited.text + s"\n-- $editTime --"
|
edited.text + s"\n-- $editTime --"
|
||||||
).entities(entities toArray:_*)
|
).entities(entities toArray:_*)
|
||||||
lastNotify_messageId = null
|
lastNotify_messageId = None
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -101,9 +101,9 @@ class MornyReport (using coeur: MornyCoeur) {
|
|||||||
|
|
||||||
def reportCoeurExit (): Unit = {
|
def reportCoeurExit (): Unit = {
|
||||||
val causedTag = coeur.exitReason match
|
val causedTag = coeur.exitReason match
|
||||||
case u: User => u.fullnameRefHTML
|
case None => "UNKNOWN reason"
|
||||||
case n if n == null => "UNKNOWN reason"
|
case u: Some[User] => u.get.fullnameRefHTML
|
||||||
case a: AnyRef => /*language=html*/ s"<code>${h(a.toString)}</code>"
|
case a: Some[_] => /*language=html*/ s"<code>${h(a.get.toString)}</code>"
|
||||||
executeReport(SendMessage(
|
executeReport(SendMessage(
|
||||||
coeur.config.reportToChat,
|
coeur.config.reportToChat,
|
||||||
// language=html
|
// language=html
|
||||||
|
@ -29,9 +29,9 @@ object MornyInformation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//noinspection ScalaWeakerAccess
|
//noinspection ScalaWeakerAccess
|
||||||
def getRuntimeHostname: String | Null = {
|
def getRuntimeHostname: Option[String] = {
|
||||||
try InetAddress.getLocalHost.getHostName
|
try Some(InetAddress.getLocalHost.getHostName)
|
||||||
catch case _: UnknownHostException => null
|
catch case _: UnknownHostException => None
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get
|
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get
|
||||||
|
@ -13,17 +13,17 @@ object TelegramImages {
|
|||||||
|
|
||||||
class AssetsFileImage (assetsPath: String) {
|
class AssetsFileImage (assetsPath: String) {
|
||||||
|
|
||||||
private var cache: Array[Byte]|Null = _
|
private var cache: Option[Array[Byte]] = None
|
||||||
|
|
||||||
@throws[AssetsException]
|
@throws[AssetsException]
|
||||||
def get:Array[Byte] =
|
def get:Array[Byte] =
|
||||||
if cache eq null then read()
|
if cache isEmpty then read()
|
||||||
cache
|
cache.get
|
||||||
|
|
||||||
@throws[AssetsException]
|
@throws[AssetsException]
|
||||||
private def read (): Unit = {
|
private def read (): Unit = {
|
||||||
Using ((MornyAssets.pack getResource assetsPath)read) { stream =>
|
Using ((MornyAssets.pack getResource assetsPath)read) { stream =>
|
||||||
try { this.cache = stream.readAllBytes() }
|
try { this.cache = Some(stream.readAllBytes()) }
|
||||||
catch case e: IOException => {
|
catch case e: IOException => {
|
||||||
throw AssetsException(e)
|
throw AssetsException(e)
|
||||||
}
|
}
|
||||||
|
27
src/main/scala/cc/sukazyo/cono/morny/util/UseSelect.scala
Normal file
27
src/main/scala/cc/sukazyo/cono/morny/util/UseSelect.scala
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package cc.sukazyo.cono.morny.util
|
||||||
|
|
||||||
|
import scala.util.boundary
|
||||||
|
|
||||||
|
/** Useful utils of select one specific value in the given values.
|
||||||
|
*
|
||||||
|
* contains:
|
||||||
|
* - [[select()]] can select one value which is not [[Null]].
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
object UseSelect {
|
||||||
|
|
||||||
|
/** Select the non-null value in the given values.
|
||||||
|
*
|
||||||
|
* @tparam T The value's type.
|
||||||
|
* @param values Given values, may be a T value or [[Null]].
|
||||||
|
* @return The first non-null value in the given values, or [[Null]] if
|
||||||
|
* there's no non-null value.
|
||||||
|
*/
|
||||||
|
def select [T] (values: T|Null*): T|Null = {
|
||||||
|
boundary[T|Null] {
|
||||||
|
for (i <- values) if i != null then boundary.break(i)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user