add support for inline bilibili preview share. cha some social share query result names

- for Bilibili
  - from "[bilbili] Share video / avXXX/BVXXX" to "[Bilibili] Video avXXX/BVXXX", and also added description
  - from "[tweet] Share as VxTwitter/Fix-Tweet" to "[Twitter/X][VXTwitter/Fix-Tweet] $screenName/statusId"
  - from "[Xiaohongshu] Share Link [$id]" to "[Xiaohongshu] Note $id.
    - also added description.
    - if the note is from a share url, then the share url will be show in description
This commit is contained in:
A.C.Sukazyo Eyre 2024-08-23 22:30:27 +08:00
parent de522b2dd6
commit 0b560180f4
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
6 changed files with 86 additions and 35 deletions

View File

@ -1,15 +1,11 @@
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, SendPhoto} import com.pengrad.telegrambot.request.SendMessage
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
import scala.language.postfixOps import scala.language.postfixOps
@ -20,20 +16,6 @@ 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

@ -4,14 +4,16 @@ 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.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.extra.{twitter, weibo, BilibiliForms}
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.data.social.{SocialTwitterParser, SocialWeiboParser}
import cc.sukazyo.cono.morny.extra.BilibiliForms.{BiliB23, BiliVideoId}
import cc.sukazyo.cono.morny.extra.bilibili.XWebAPI
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
import com.pengrad.telegrambot.request.{SendMessage, SendSticker} import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker}
class OnGetSocial (using coeur: MornyCoeur) extends EventListener { class OnGetSocial (using coeur: MornyCoeur) extends EventListener {
@ -69,10 +71,43 @@ object OnGetSocial {
succeed += 1 succeed += 1
tryFetchSocialOfWeibo(f) tryFetchSocialOfWeibo(f)
}) })
{
val bilibiliVideos: List[BiliVideoId] = text match
case Left(texts) =>
BiliVideoId.searchIn(texts) ::: BiliB23.searchIn(texts).map(_.toVideoId)
case Right(url) =>
try BilibiliForms.parse_videoUrl(url) :: Nil
catch case _: IllegalArgumentException =>
try BiliVideoId.matchUrl(BilibiliForms.destructB23Url(url)) :: Nil
catch case _: Exception => Nil
bilibiliVideos.foreach( video =>
succeed += 1
tryFetchSocialOfBilibili(video)
)
}
succeed > 0 succeed > 0
} }
private def tryFetchSocialOfBilibili (video: BiliVideoId)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = {
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
val video_info = XWebAPI.get_view(video)
coeur.account exec new SendPhoto(
replyChat,
video_info.data.pic
).replyToMessageId(replyToMessage)
.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)
}
private def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) = private def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) =
import io.circe.{DecodingFailure, ParsingFailure} import io.circe.{DecodingFailure, ParsingFailure}
import sttp.client3.SttpClientException import sttp.client3.SttpClientException

View File

@ -8,8 +8,6 @@ import scala.language.postfixOps
class ShareToolBilibili extends ITelegramQuery { class ShareToolBilibili extends ITelegramQuery {
private val TITLE_BILI_AV = "[bilibili] Share video / av"
private val TITLE_BILI_BV = "[bilibili] Share video / BV"
private val ID_PREFIX_BILI_AV = "[morny/share/bili/av]" private val ID_PREFIX_BILI_AV = "[morny/share/bili/av]"
private val ID_PREFIX_BILI_BV = "[morny/share/bili/bv]" private val ID_PREFIX_BILI_BV = "[morny/share/bili/bv]"
private val SHARE_FORMAT_HTML = "<a href='%s'>%s</a>" private val SHARE_FORMAT_HTML = "<a href='%s'>%s</a>"
@ -30,13 +28,17 @@ class ShareToolBilibili extends ITelegramQuery {
List( List(
InlineQueryUnit(InlineQueryResultArticle( InlineQueryUnit(InlineQueryResultArticle(
inlineQueryId(ID_PREFIX_BILI_AV + it.av), inlineQueryId(ID_PREFIX_BILI_AV + it.av),
TITLE_BILI_AV + it.av, s"[Bilibili] Video av${it.av}",
InputTextMessageContent(formatShareHTML(it.avLink, it.toAvString)).parseMode(ParseMode HTML) InputTextMessageContent(formatShareHTML(it.avLink, it.toAvString)).parseMode(ParseMode HTML)
).description(
s"Video URL only. Aka BV${it.bv}"
)), )),
InlineQueryUnit(InlineQueryResultArticle( InlineQueryUnit(InlineQueryResultArticle(
inlineQueryId(ID_PREFIX_BILI_BV + it.bv), inlineQueryId(ID_PREFIX_BILI_BV + it.bv),
TITLE_BILI_BV + it.bv, s"[Bilibili] Video BV${it.bv}",
InputTextMessageContent(formatShareHTML(it.bvLink, it.toBvString)).parseMode(ParseMode HTML) InputTextMessageContent(formatShareHTML(it.bvLink, it.toBvString)).parseMode(ParseMode HTML)
).description(
s"Video URL only. Aka av${it.av}"
)) ))
) )
) )

View File

@ -4,7 +4,11 @@ import cc.sukazyo.cono.morny.data.social.{SocialTwitterParser, SocialWeiboParser
import cc.sukazyo.cono.morny.extra.{twitter, weibo} import cc.sukazyo.cono.morny.extra.{twitter, weibo}
import cc.sukazyo.cono.morny.extra.twitter.FXApi import cc.sukazyo.cono.morny.extra.twitter.FXApi
import cc.sukazyo.cono.morny.extra.weibo.MApi import cc.sukazyo.cono.morny.extra.weibo.MApi
import cc.sukazyo.cono.morny.extra.BilibiliForms.{BiliB23, BiliVideoId}
import cc.sukazyo.cono.morny.extra.bilibili.XWebAPI
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.Update
import com.pengrad.telegrambot.model.request.{InlineQueryResultPhoto, ParseMode}
class ShareToolSocialContent extends ITelegramQuery { class ShareToolSocialContent extends ITelegramQuery {
@ -13,7 +17,33 @@ class ShareToolSocialContent extends ITelegramQuery {
val query = event.inlineQuery.query val query = event.inlineQuery.query
if query == null then return null if query == null then return null
twitterTweets(query) ::: weiboStatus(query) twitterTweets(query) ::: weiboStatus(query) ::: bilibiliVideos(query)
}
private def bilibiliVideos (query: String): List[InlineQueryUnit[_]] = {
val results: List[(String, BiliVideoId)] =
BiliVideoId.searchIn(query).map(x => (x.toString, x)) ++
BiliB23.searchIn(query).map(x => (x.toString, x.toVideoId))
results.map { (_, video) =>
val video_info = XWebAPI.get_view(video)
InlineQueryUnit(InlineQueryResultPhoto(
"[morny/share/bilibili/video/preview]" + video.av + "/" + video.bv,
video_info.data.pic,
video_info.data.pic
).title(
s"[Bilibili] ${video_info.data.title}"
).description(
s"av${video.av} / BV${video.bv} - Preview"
).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))
}
} }

View File

@ -9,9 +9,9 @@ import scala.language.postfixOps
class ShareToolTwitter extends ITelegramQuery { class ShareToolTwitter extends ITelegramQuery {
private val TITLE_VX = "[tweet] Share as VxTwitter" private val TITLE_VX = "[Twitter/X][VxTwitter]"
private val ID_PREFIX_VX = "[morny/share/twitter/vx_url]" private val ID_PREFIX_VX = "[morny/share/twitter/vx_url]"
private val TITLE_FX = "[tweet] Share as Fix-Tweet" private val TITLE_FX = "[Twitter/X][Fix-Tweet]"
private val ID_PREFIX_FX = "[morny/share/twitter/fx_url]" private val ID_PREFIX_FX = "[morny/share/twitter/fx_url]"
override def query (event: Update): List[InlineQueryUnit[_]] | Null = { override def query (event: Update): List[InlineQueryUnit[_]] | Null = {
@ -21,7 +21,7 @@ class ShareToolTwitter extends ITelegramQuery {
def getQueryTweetId (prefix: String, tweet: TweetUrlInformation): String = def getQueryTweetId (prefix: String, tweet: TweetUrlInformation): String =
prefix + tweet.hashCode prefix + tweet.hashCode
def getTweetName (title_prefix: String, tweet: TweetUrlInformation): String = def getTweetName (title_prefix: String, tweet: TweetUrlInformation): String =
s"$title_prefix ${tweet.screenName}.${tweet.statusId}" s"$title_prefix ${tweet.screenName}/${tweet.statusId}"
twitter.guessTweetUrl(event.inlineQuery.query).flatMap(tweet => twitter.guessTweetUrl(event.inlineQuery.query).flatMap(tweet =>
List( List(

View File

@ -5,7 +5,7 @@ import com.pengrad.telegrambot.model.request.InlineQueryResultArticle
class ShareToolXhs extends ITelegramQuery { class ShareToolXhs extends ITelegramQuery {
private val TITLE = "[Xiaohongshu] Share Link" private val TITLE = "[Xiaohongshu] Note"
private val ID = "[morny/share/xhs/link]" private val ID = "[morny/share/xhs/link]"
override def query (event: Update): List[InlineQueryUnit[_]] | Null = { override def query (event: Update): List[InlineQueryUnit[_]] | Null = {
@ -15,22 +15,24 @@ class ShareToolXhs extends ITelegramQuery {
val content = inlineQuery.query val content = inlineQuery.query
def getTitle (xhsLink: XHSLink): String = { def getTitle (xhsLink: XHSLink): String = {
s"$TITLE [${xhsLink.exploreId}]" s"$TITLE ${xhsLink.exploreId}"
} }
val xhsLinks: List[(String, XHSLink)] = { val xhsLinks: List[(String, XHSLink, Option[String])] = {
XHSLink.searchUrls(content).map { XHSLink.searchUrls(content).map {
case xhsLink: XHSLink => (xhsLink.toString, xhsLink) case xhsLink: XHSLink => (xhsLink.toString, xhsLink, None)
case shareLink: XHSLink.ShareLink => case shareLink: XHSLink.ShareLink =>
(shareLink.toString, shareLink.getXhsLink) (shareLink.toString, shareLink.getXhsLink, Some(shareLink.link))
} }
} }
xhsLinks.map((uniqueId, xhsLink) => xhsLinks.map((uniqueId, xhsLink, maybeFromShare) =>
InlineQueryUnit(InlineQueryResultArticle( InlineQueryUnit(InlineQueryResultArticle(
ID+uniqueId, ID+uniqueId,
getTitle(xhsLink), getTitle(xhsLink),
xhsLink.link xhsLink.link
).description(
"URL only." + (if maybeFromShare.nonEmpty then s" from $maybeFromShare" else "")
)) ))
) )