Compare commits

...

3 Commits

9 changed files with 165 additions and 8 deletions

View File

@ -28,11 +28,11 @@ class EventEnv (
//noinspection UnitMethodIsParameterless //noinspection UnitMethodIsParameterless
def setEventOk: Unit = def setEventOk: Unit =
_status += State.OK(StackUtils.getStackTrace(1)(1)) _status += State.OK(StackUtils.getStackTrace(1)(0))
//noinspection UnitMethodIsParameterless //noinspection UnitMethodIsParameterless
def setEventCanceled: Unit = def setEventCanceled: Unit =
_status += State.CANCELED(StackUtils.getStackTrace(1)(1)) _status += State.CANCELED(StackUtils.getStackTrace(1)(0))
def state: State|Null = def state: State|Null =
_status.lastOption match _status.lastOption match

View File

@ -1,4 +1,5 @@
package cc.sukazyo.cono.morny.bot.command package cc.sukazyo.cono.morny.bot.command
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias
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
@ -7,13 +8,25 @@ import cc.sukazyo.cono.morny.daemon.MornyReport
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
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.TelegramExtensions.Bot.exec import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.{Chat, Update}
import com.pengrad.telegrambot.request.SendSticker import com.pengrad.telegrambot.request.SendSticker
import scala.language.postfixOps import scala.language.postfixOps
class MornyManagers (using coeur: MornyCoeur) { class MornyManagers (using coeur: MornyCoeur) {
/** Check if the command is directly targeted to Morny.
*
* If and only if the command is in private chat, or the command is in group chat AND the command target is explicitly
* set to Morny's username, then the command is targeted to Morny.
*
* This aims to reduce the mis-trigger on some commands that are easily collisions to other bots and are important.
*/
def isMornyTargeted (event: Update, command: InputCommand): Boolean =
if event.message.chat.`type` != Chat.Type.Private && command.target != coeur.username then false
else if command.target != null && command.target != coeur.username then false
else true
object Exit extends ITelegramCommand { object Exit extends ITelegramCommand {
override val name: String = "exit" override val name: String = "exit"
@ -23,6 +36,10 @@ class MornyManagers (using coeur: MornyCoeur) {
override def execute (using command: InputCommand, event: Update): Unit = { override def execute (using command: InputCommand, event: Update): Unit = {
if !isMornyTargeted(event, command) then
logger debug "seems command does not targeted to morny, skipped"
return
val user = event.message.from val user = event.message.from
if (coeur.trusted isTrusted user.id) { if (coeur.trusted isTrusted user.id) {
@ -58,6 +75,10 @@ class MornyManagers (using coeur: MornyCoeur) {
override def execute (using command: InputCommand, event: Update): Unit = { override def execute (using command: InputCommand, event: Update): Unit = {
if !isMornyTargeted(event, command) then
logger debug "seems command does not targeted to morny, skipped"
return
val user = event.message.from val user = event.message.from
if (coeur.trusted isTrusted user.id) { if (coeur.trusted isTrusted user.id) {

View File

@ -1,11 +1,15 @@
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.extra.BilibiliForms
import cc.sukazyo.cono.morny.extra.bilibili.XWebAPI
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
import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.request.ParseMode
import com.pengrad.telegrambot.request.SendMessage import com.pengrad.telegrambot.request.{SendMessage, SendPhoto}
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
import scala.language.postfixOps import scala.language.postfixOps
@ -16,6 +20,20 @@ class Testing (using coeur: MornyCoeur) extends ISimpleCommand {
override def execute (using command: InputCommand, event: Update): Unit = { override def execute (using command: InputCommand, event: Update): Unit = {
val video = BilibiliForms.parse_videoUrl(command.args.mkString(" "))
val video_info = XWebAPI.get_view(video)
coeur.account exec new SendPhoto(
event.message.chat.id,
video_info.data.pic
).replyToMessageId(event.message.messageId)
.caption(
// language=html
s"""<a href="https://www.bilibili.com/video/av${video.av}"><b>${h(video_info.data.title)}</b></a>
| <a href="https://space.bilibili.com/${video_info.data.owner.mid}">@${h(video_info.data.owner.name)}</a>
|${h(video_info.data.desc)}""".stripMargin
).parseMode(ParseMode.HTML)
coeur.account exec new SendMessage( coeur.account exec new SendMessage(
event.message.chat.id, event.message.chat.id,
// language=html // language=html

View File

@ -6,7 +6,6 @@ import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, MornyQueries}
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.logger import cc.sukazyo.cono.morny.Log.logger
import com.google.gson.Gson import com.google.gson.Gson
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
@ -32,8 +31,7 @@ class MornyOnInlineQuery (using queryManager: MornyQueries) (using coeur: MornyC
if (results isEmpty) return; if (results isEmpty) return;
logger debug resultAnswers.map(Gson().toJson(_)).mkString("\n") logger trace "Query answers:\n" + resultAnswers.map(" " + Gson().toJson(_)).mkString("\n")
coeur.account exec AnswerInlineQuery( coeur.account exec AnswerInlineQuery(
update.inlineQuery.id, resultAnswers toArray:_* update.inlineQuery.id, resultAnswers toArray:_*
).cacheTime(cacheTime).isPersonal(isPersonal) ).cacheTime(cacheTime).isPersonal(isPersonal)

View File

@ -6,7 +6,7 @@ import com.pengrad.telegrambot.model.request.InlineQueryResult
object InlineQueryUnit { object InlineQueryUnit {
object defaults: object defaults:
val CACHE_TIME = 1 val CACHE_TIME = 300
val IS_PERSONAL = false val IS_PERSONAL = false
} }

View File

@ -0,0 +1,38 @@
package cc.sukazyo.cono.morny.extra.bilibili
import cc.sukazyo.cono.morny.extra.BilibiliForms.BiliVideoId
import cc.sukazyo.cono.morny.util.SttpPublic.mornyBasicRequest
import sttp.client3.{asString, RequestT}
import sttp.client3.okhttp.OkHttpSyncBackend
import sttp.model.Uri
object XWebAPI {
private val URL_BASE = "https://api.bilibili.com/x/web-interface"
private lazy val http_client = OkHttpSyncBackend()
def get_view (video: BiliVideoId)(using
http_client: sttp.client3.SttpBackend[sttp.client3.Identity, _] = http_client,
basic_request: RequestT[sttp.client3.Empty, Either[String, String], Any] = mornyBasicRequest
): XWebResponse[XWebView] = {
val request_url = Uri.unsafeParse(URL_BASE)
.addPath("view")
.addParams("aid" -> video.av.toString)
val response = basic_request
.get(request_url)
.response(asString.getRight)
.send(http_client)
val response_body = response.body
io.circe.parser.parse(response_body)
.toTry.get
.as[XWebResponse[XWebView]]
.toTry.get
}
}

View File

@ -0,0 +1,8 @@
package cc.sukazyo.cono.morny.extra.bilibili
case class XWebResponse [T] (
code: Int,
message: String,
ttl: Int,
data: T
)

View File

@ -0,0 +1,59 @@
package cc.sukazyo.cono.morny.extra.bilibili
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochSeconds
import cc.sukazyo.cono.morny.util.circe.Ignore
import io.circe.Codec
case class XWebView (
bvid: String,
aid: Long,
videos: Int,
tid: Int,
tname: String,
copyright: Int,
pic: String,
title: String,
pubdate: EpochSeconds,
ctime: EpochSeconds,
desc: String,
desc_v2: List[Ignore],
state: Int,
duration: Int,
forward: Option[Ignore],
mission_id: Option[Ignore],
redirect_url: Option[Ignore],
rights: Option[Ignore],
owner: XWebView.User,
stat: Ignore,
dynamic: String,
cid: Int,
dimension: Ignore,
premiere: Ignore,
teenage_mode: Int,
is_chargeable_season: Boolean,
is_story: Boolean,
no_cache: Boolean,
pages: List[Ignore],
subtitle: Ignore,
staff: Option[List[Ignore]],
is_season_display: Boolean,
use_grab: Option[Ignore],
honor_reply: Option[Ignore],
like_icon: Option[String],
argue_info: Option[Ignore]
)
object XWebView {
case class User (
mid: Long,
name: String,
face: String,
)
import io.circe.generic.semiauto.deriveCodec
implicit val codec: Codec[XWebView] = deriveCodec
implicit val codec_User: Codec[User] = deriveCodec
implicit val codec_with_XWebResponse: Codec[XWebResponse[XWebView]] = deriveCodec
}

View File

@ -0,0 +1,15 @@
package cc.sukazyo.cono.morny.util.circe
import io.circe.{Codec, HCursor, Json}
import io.circe.Decoder.Result
case class Ignore ()
object Ignore {
implicit val codec_ignore: Codec[Ignore] = new Codec[Ignore] {
override def apply (c: HCursor): Result[Ignore] = Right(Ignore())
override def apply (a: Ignore): Json = Json.Null
}
}