From cd21df115f78b29fa606f532c7fc3c3bed6d86f2 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sat, 3 May 2025 19:11:01 +0800 Subject: [PATCH] fix bilibili video false-positive match - fix BilibiliForms.BiliVideoId.searchIn may get false-positive results in random english texts - add more event listener details log on EventListenerManager handled listener errors --- gradle.properties | 2 +- .../morny/bot/api/EventListenerManager.scala | 55 ++++++++++------ .../cono/morny/bot/event/OnGetSocial.scala | 29 ++++++--- .../cono/morny/extra/BilibiliForms.scala | 2 +- .../morny/test/extra/BilibiliFormsTest.scala | 62 +++++++++++++++++++ 5 files changed, 118 insertions(+), 32 deletions(-) diff --git a/gradle.properties b/gradle.properties index ff06b9c..2cda038 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ MORNY_ARCHIVE_NAME = morny-coeur MORNY_CODE_STORE = https://github.com/Eyre-S/Coeur-Morny-Cono MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s -VERSION = 1.4.1 +VERSION = 1.4.2-alpha.1 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala index 7a810f4..8098025 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala @@ -24,60 +24,75 @@ class EventListenerManager (using coeur: MornyCoeur) extends UpdatesListener { this.listeners ++= listeners private class EventRunner (using update: Update) extends Thread { + this setName s"upd-${update.updateId()}-nn" - private def updateThreadName (t: String): Unit = - this setName s"upd-${update.updateId()}-$t" + private var currentSubevent: String = "" + private var currentListener: String = "" + private def setRunnerStatus (subevent: String): Unit = { + currentSubevent = subevent + this setName s"upd-${update.updateId()}-$subevent" + } + + private def setRunningListener (listener: EventListener): Unit = + currentListener = listener.getClass.getName override def run (): Unit = { given env: EventEnv = EventEnv(update) - for (i <- listeners) + for (i <- listeners) { + setRunningListener(i) if (i.executeFilter) runEventListener(i) - for (i <- listeners) + } + for (i <- listeners) { + setRunningListener(i) runEventPost(i) + } } private def runEventPost (i: EventListener)(using EventEnv): Unit = { - updateThreadName("#post") + setRunnerStatus("#post") i.atEventPost } private def runEventListener (i: EventListener)(using EventEnv): Unit = { try { - updateThreadName("message") + setRunnerStatus("message") if update.message ne null then i.onMessage - updateThreadName("edited-message") + setRunnerStatus("edited-message") if update.editedMessage ne null then i.onEditedMessage - updateThreadName("channel-post") + setRunnerStatus("channel-post") if update.channelPost ne null then i.onChannelPost - updateThreadName("edited-channel-post") + setRunnerStatus("edited-channel-post") if update.editedChannelPost ne null then i.onEditedChannelPost - updateThreadName("inline-query") + setRunnerStatus("inline-query") if update.inlineQuery ne null then i.onInlineQuery - updateThreadName("chosen-inline-result") + setRunnerStatus("chosen-inline-result") if update.chosenInlineResult ne null then i.onChosenInlineResult - updateThreadName("callback-query") + setRunnerStatus("callback-query") if update.callbackQuery ne null then i.onCallbackQuery - updateThreadName("shipping-query") + setRunnerStatus("shipping-query") if update.shippingQuery ne null then i.onShippingQuery - updateThreadName("pre-checkout-query") + setRunnerStatus("pre-checkout-query") if update.preCheckoutQuery ne null then i.onPreCheckoutQuery - updateThreadName("poll") + setRunnerStatus("poll") if update.poll ne null then i.onPoll - updateThreadName("poll-answer") + setRunnerStatus("poll-answer") if update.pollAnswer ne null then i.onPollAnswer - updateThreadName("my-chat-member") + setRunnerStatus("my-chat-member") if update.myChatMember ne null then i.onMyChatMemberUpdated - updateThreadName("chat-member") + setRunnerStatus("chat-member") if update.chatMember ne null then i.onChatMemberUpdated - updateThreadName("chat-join-request") + setRunnerStatus("chat-join-request") if update.chatJoinRequest ne null then i.onChatJoinRequest } catch case e => { val errorMessage = StringBuilder() - errorMessage ++= "Event throws unexpected exception:\n" + errorMessage ++= "Event throws unexpected exception!\n" + errorMessage ++= s"current event_listener = $currentListener\n" + errorMessage ++= s"current subevent = $currentSubevent\n" + errorMessage ++= s"error message :" errorMessage ++= (exceptionLog(e) indent 4) e match case actionFailed: EventRuntimeException.ActionFailed => diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnGetSocial.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnGetSocial.scala index 2a63020..848f1c0 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnGetSocial.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnGetSocial.scala @@ -92,16 +92,25 @@ object OnGetSocial { } private def tryFetchSocialOfBilibili (video: BiliVideoId)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = { - - val video_info = XWebAPI.get_view(video) - coeur.account exec new SendPhoto( - replyChat, - video_info.data.pic - ).replyToMessageId(replyToMessage) - .caption( - SocialBilibiliParser.printsBilibiliVideoCaption(video, video_info.data) - ).parseMode(ParseMode.HTML) - + import io.circe.{DecodingFailure, ParsingFailure} + import sttp.client3.SttpClientException + try { + val video_info = XWebAPI.get_view(video) + coeur.account exec new SendPhoto( + replyChat, + video_info.data.pic + ).replyToMessageId(replyToMessage) + .caption( + SocialBilibiliParser.printsBilibiliVideoCaption(video, video_info.data) + ).parseMode(ParseMode.HTML) + } catch case e: (SttpClientException | ParsingFailure | DecodingFailure) => + coeur.account exec SendSticker( + replyChat, + TelegramStickers.ID_NETWORK_ERR + ).replyToMessageId(replyToMessage) + logger error + "Error on requesting Bilibili API\n" + exceptionLog(e) + coeur.daemons.reporter.exception(e, "Error on requesting Bilibili API") } private def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = diff --git a/src/main/scala/cc/sukazyo/cono/morny/extra/BilibiliForms.scala b/src/main/scala/cc/sukazyo/cono/morny/extra/BilibiliForms.scala index fbd4d95..a3b7e75 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/extra/BilibiliForms.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/extra/BilibiliForms.scala @@ -89,7 +89,7 @@ object BilibiliForms { } private val REGEX_BILI_ID = "((?:av|AV)(\\d{1,16})|(?:bv1|BV1)([A-HJ-NP-Za-km-z1-9]{9}))"r private val REGEX_BILI_V_PART_IN_URL_PARAM = "(?:&|^)p=(\\d+)"r - private val REGEX_BILI_VIDEO: Regex = "(?:https?://)?(?:(?:www\\.)?bilibili\\.com(?:/s)?/video/|b23\\.tv/)((?:av|AV)(\\d{1,16})|(?:bv1|BV1)([A-HJ-NP-Za-km-z1-9]{9}))/?(?:\\?((?:p=(\\d+))?.*))?|(?:av|AV)(\\d{1,16})|(?:bv1|BV1)([A-HJ-NP-Za-km-z1-9]{9})"r + private val REGEX_BILI_VIDEO: Regex = "(?:https?://)?(?:(?:www\\.)?bilibili\\.com(?:/s)?/video/|b23\\.tv/)((?:av|AV)(\\d{1,16})|(?:bv1|BV1)([A-HJ-NP-Za-km-z1-9]{9}))/?(?:\\?((?:p=(\\d+))?.*))?|(?:[^a-zA-Z0-9]|^)(?:(?:av|AV)(\\d{1,16})|(?:bv1|BV1)([A-HJ-NP-Za-km-z1-9]{9}))(?:[^a-zA-Z0-9]|$)"r /** parse a Bilibili video link to a [[BiliVideoId]] format Bilibili Video Id. * diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/extra/BilibiliFormsTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/extra/BilibiliFormsTest.scala index eb10b8c..d65a55d 100644 --- a/src/test/scala/cc/sukazyo/cono/morny/test/extra/BilibiliFormsTest.scala +++ b/src/test/scala/cc/sukazyo/cono/morny/test/extra/BilibiliFormsTest.scala @@ -94,6 +94,68 @@ class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks { } + "while searching bilibili video id from texts, " - { + + "a bare URL/id should be searched" in { + BiliVideoId.searchIn("https://b23.tv/av688730800") + .shouldEqual(List(BiliVideoId.fromAv(688730800L))) + BiliVideoId.searchIn("https://www.bilibili.com/video/bv1T24y197V2") + .shouldEqual(List(BiliVideoId.fromBv("1T24y197V2"))) + BiliVideoId.searchIn("av87529274") + .shouldEqual(List(BiliVideoId.fromAv(87529274L))) + } + + "multiple video url/id should be searched to a list that contains all valid video id" in { + BiliVideoId.searchIn( + """av18756293 + |https://b23.tv/BV1Q541167Qg + |https://www.bilibili.com/s/video/AV455017605""".stripMargin) shouldEqual List( + BiliVideoId.fromAv(18756293L), + BiliVideoId.fromBv("1Q541167Qg"), + BiliVideoId.fromAv(455017605L) + ) + } + + "the video text/url surrounded by other text with spaces should be searched" in { + BiliVideoId.searchIn("The video: av123456 is a video.") + .shouldEqual(List(BiliVideoId.fromAv(123456L))) + } + + "the video text/url surrounded by punctuation and brackets should be searched" in { + BiliVideoId.searchIn("an interesting video can be found [here](https://b23.tv/av3339987).") + .shouldEqual(List(BiliVideoId.fromAv(3339987))) + BiliVideoId.searchIn("something like BV1Q541167Qg, is odd") + .shouldEqual(List(BiliVideoId.fromBv("1Q541167Qg"))) + BiliVideoId.searchIn("tag a video #{av875543} is just like this") + .shouldEqual(List(BiliVideoId.fromAv(875543))) + } + + "the video text/url surrounded by CJK characters should be searched" in { + BiliVideoId.searchIn("视频号av114514只是一个虚构的存在") + .shouldEqual(List(BiliVideoId.fromAv(114514))) + BiliVideoId.searchIn("ビデオ番号:av114514は単なる架空の存在です") + .shouldEqual(List(BiliVideoId.fromAv(114514))) + } + + "the av/bv like text inside random texts should not be searched" in { + BiliVideoId.searchIn("3zATg9BeCUPAV1pQy8ToXOq+RSYen6winZ2OO93eyHv") + .shouldBe(empty) + BiliVideoId.searchIn("dph009ayh2w098yha9yh09dyha09av1") + .shouldBe(empty) + BiliVideoId.searchIn("av18214670816042164014") + .shouldBe(empty) + BiliVideoId.searchIn("av1821dwayhd80eawd") + .shouldBe(empty) + BiliVideoId.searchIn("dph0xhoHOAh2wBBV1Q541167QgihOHhoXHOAa") + .shouldBe(empty) + BiliVideoId.searchIn("BV1Q541167QgHOXhapoiwhrdpiAHPDXCiahpc") + .shouldBe(empty) + BiliVideoId.searchIn("dapihwdfpiHpi;dcahnPI:HDCBNpiwHPIDABV1Q541167Qg") + .shouldBe(empty) + } + + } + "b23.tv share url" - { "should be get" - {