cha inline social content results rules

now it follows the following rules:

1. If there contains images
  1.1 If there supports mosaic image, then provide a result with mosaic image with text content.
  1.2 If the previous one is not supported, then provide a result with the first image with text content.
  1.3 If the previous two are not supported, then provide a result with only text content.
  1.4 And for each image that supports, provide a image only (with a source url) result.
2. If there contains no image, just provide the text content result.
This commit is contained in:
A.C.Sukazyo Eyre 2024-09-11 22:11:46 +08:00
parent bd204a3cd7
commit 7c90b1f9af
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
3 changed files with 78 additions and 48 deletions

View File

@ -9,6 +9,8 @@ import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId
import com.pengrad.telegrambot.model.request.* import com.pengrad.telegrambot.model.request.*
import com.pengrad.telegrambot.request.{SendMediaGroup, SendMessage} import com.pengrad.telegrambot.request.{SendMediaGroup, SendMessage}
import scala.collection.mutable.ListBuffer
/** Model of social networks' status. for example twitter tweet or /** Model of social networks' status. for example twitter tweet or
* weibo status. * weibo status.
* *
@ -61,9 +63,12 @@ case class SocialContent (
} }
def genInlineQueryResults (using id_head: String, id_param: Any, name: String): List[InlineQueryUnit[?]] = { def genInlineQueryResults (using id_head: String, id_param: Any, name: String): List[InlineQueryUnit[?]] = {
( val results = ListBuffer[InlineQueryUnit[?]]()
if (medias_mosaic nonEmpty) && (medias_mosaic.get.t == Photo) && medias_mosaic.get.isInstanceOf[SocialMediaWithUrl] then
// It has multi medias, and the mosaic version is provided. // It has multi medias, and the mosaic version is provided,
// uses the mosaic version to provide an image+text result.
if (medias.length > 1) && (medias_mosaic nonEmpty) && (medias_mosaic.get.t == Photo) && medias_mosaic.get.isInstanceOf[SocialMediaWithUrl] then
results +=
InlineQueryUnit(InlineQueryResultPhoto( InlineQueryUnit(InlineQueryResultPhoto(
s"[$id_head/photo/mosaic]$id_param", s"[$id_head/photo/mosaic]$id_param",
medias_mosaic.get.asInstanceOf[SocialMediaWithUrl].url, medias_mosaic.get.asInstanceOf[SocialMediaWithUrl].url,
@ -71,49 +76,73 @@ case class SocialContent (
).title( ).title(
s"$name $title" s"$name $title"
).description( ).description(
s"Pictures are combined. $description" s"Medias combined. $description"
).caption( ).caption(
text_html text_html
).parseMode(ParseMode.HTML)) :: Nil ).parseMode(ParseMode.HTML))
else if (medias nonEmpty) && (medias.head.t == Photo) then
val media = medias.head // It has medias, and the first media is URL formatted, then provide the first media with content,
media match // uses the first media to provide an image1+text result.
case media_url: SocialMediaWithUrl => else if (medias nonEmpty) && medias.head.isInstanceOf[SocialMediaWithUrl] then
// the medias is provided, and the first one is in URL format. val media = medias.head.asInstanceOf[SocialMediaWithUrl]
// it may still contain multiple medias. results +=
// although in only two implementations, the Twitter implementation will always give a mosaic InlineQueryUnit(InlineQueryResultPhoto(
// pic; and the Weibo implementation never uses URL formatted medias. s"[$id_head/photo/0/contented]$id_param",
InlineQueryUnit(InlineQueryResultPhoto( media.url,
s"[$id_head/photo/0]$id_param", thumbnailOrElse(media.url)
media_url.url, ).title(
thumbnailOrElse(media_url.url) s"$name $title"
).title( ).description(
s"$name $title" s"Pic 1/${medias.length}, with content. $description"
).description( ).caption(
s"Pic 1. $description" text_html
).caption( ).parseMode(ParseMode.HTML))
text_html
).parseMode(ParseMode.HTML)) :: Nil // It has medias, and all the previous method failed,
case _ => // then a plain text version will be provided.
// the medias are provided but are not in URL format. else if medias.nonEmpty then
// in this case, the plain text version will be used. results +=
InlineQueryUnit(InlineQueryResultArticle( InlineQueryUnit(InlineQueryResultArticle(
s"[$id_head/text_only]$id_param", s"[$id_head/text_only]$id_param",
s"$name $title", s"$name $title",
InputTextMessageContent(text_withPicPlaceholder).parseMode(ParseMode.HTML) InputTextMessageContent(text_withPicPlaceholder).parseMode(ParseMode.HTML)
).description( ).description(
s"Plain text only. $description" s"Plain text. $description"
)) :: Nil ))
else
// There are never any medias. // The medias is provided, iterate all the medias and provide a media-only result.
// Note that the media are not URL formatted will be ignored.
val resultsMediaOnly: IndexedSeq[InlineQueryUnit[?]] = if medias nonEmpty then for mediaId <- medias.indices yield {
val media = medias(mediaId)
media match
case media_url: SocialMediaWithUrl =>
InlineQueryUnit(InlineQueryResultPhoto(
s"[$id_head/photo/$mediaId/bare]$id_param",
media_url.url,
thumbnailOrElse(media_url.url)
).title(
s"$name $title"
).description(
s"Pic ${mediaId+1}/${medias.length}, pic only. $description"
).caption(
media_url.sourceUrl
))
case _ => null
} else Nil.toIndexedSeq
results ++= resultsMediaOnly
// If there are no any medias, use the plain text mode.
if results isEmpty then
results +=
InlineQueryUnit(InlineQueryResultArticle( InlineQueryUnit(InlineQueryResultArticle(
s"[$id_head/text]$id_param", s"[$id_head/text]$id_param",
s"$name $title", s"$name $title",
InputTextMessageContent(text_html).parseMode(ParseMode.HTML) InputTextMessageContent(text_html).parseMode(ParseMode.HTML)
).description( ).description(
description description
)) :: Nil ))
) ::: Nil
results.toList
} }
} }
@ -123,16 +152,16 @@ object SocialContent {
enum SocialMediaType: enum SocialMediaType:
case Photo case Photo
case Video case Video
sealed trait SocialMedia(val t: SocialMediaType) { sealed trait SocialMedia(val t: SocialMediaType, val sourceUrl: String) {
def genTelegramInputMedia: InputMedia[?] def genTelegramInputMedia: InputMedia[?]
} }
case class SocialMediaWithUrl (url: String)(t: SocialMediaType) extends SocialMedia(t) { case class SocialMediaWithUrl (url: String)(t: SocialMediaType, sourceUrl: String) extends SocialMedia(t, sourceUrl) {
override def genTelegramInputMedia: InputMedia[_] = override def genTelegramInputMedia: InputMedia[_] =
t match t match
case Photo => InputMediaPhoto(url) case Photo => InputMediaPhoto(url)
case Video => InputMediaVideo(url) case Video => InputMediaVideo(url)
} }
case class SocialMediaWithBytesData (data: Array[Byte])(t: SocialMediaType) extends SocialMedia(t) { case class SocialMediaWithBytesData (data: Array[Byte])(t: SocialMediaType, sourceUrl: String) extends SocialMedia(t, sourceUrl) {
override def genTelegramInputMedia: InputMedia[_] = override def genTelegramInputMedia: InputMedia[_] =
t match t match
case Photo => InputMediaPhoto(data) case Photo => InputMediaPhoto(data)

View File

@ -51,18 +51,18 @@ object SocialTwitterParser {
( (
media.photos match media.photos match
case None => List.empty case None => List.empty
case Some(photos) => for i <- photos yield SocialMediaWithUrl(i.url)(Photo) case Some(photos) => for i <- photos yield SocialMediaWithUrl(i.url)(Photo, tweet.url)
) ::: ( ) ::: (
media.videos match media.videos match
case None => List.empty case None => List.empty
case Some(videos) => for i <- videos yield SocialMediaWithUrl(i.url)(Video) case Some(videos) => for i <- videos yield SocialMediaWithUrl(i.url)(Video, tweet.url)
) )
val thumbnail = val thumbnail =
if media.videos.nonEmpty then if media.videos.nonEmpty then
Some(SocialMediaWithUrl(media.videos.get.head.thumbnail_url)(Photo)) Some(SocialMediaWithUrl(media.videos.get.head.thumbnail_url)(Photo, tweet.url))
else None else None
val mediaMosaic = media.mosaic match val mediaMosaic = media.mosaic match
case Some(mosaic) => Some(SocialMediaWithUrl(mosaic.formats.jpeg)(Photo)) case Some(mosaic) => Some(SocialMediaWithUrl(mosaic.formats.jpeg)(Photo, tweet.url))
case None => None case None => None
SocialContent( SocialContent(
if title.nonEmpty then title else if title.nonEmpty then title else

View File

@ -27,27 +27,28 @@ object SocialWeiboParser {
@throws[HttpError[?] | SttpClientException | ParsingFailure | DecodingFailure] @throws[HttpError[?] | SttpClientException | ParsingFailure | DecodingFailure]
def parseMStatus (api: MApi[MStatus])(originUrl: String): SocialContent = { def parseMStatus (api: MApi[MStatus])(originUrl: String): SocialContent = {
val statusUrl: String = genWeiboStatusUrl(StatusUrlInfo(api.data.user.id.toString, api.data.id))
val content = val content =
// language=html // language=html
s"""🔸<b><a href="${api.data.user.profile_url}">${h(api.data.user.screen_name)}</a></b> s"""🔸<b><a href="${api.data.user.profile_url}">${h(api.data.user.screen_name)}</a></b>
| |
|${ch(api.data.text)} |${ch(api.data.text)}
|${parseMStatus_forRetweeted(api.data)} |${parseMStatus_forRetweeted(api.data)}
|<i><a href="${genWeiboStatusUrl(StatusUrlInfo(api.data.user.id.toString, api.data.id))}">${h(api.data.created_at)}</a></i>""".stripMargin |<i><a href="$statusUrl">${h(api.data.created_at)}</a></i>""".stripMargin
val content_withPicPlaceholder = val content_withPicPlaceholder =
// language=html // language=html
s"""🔸<b><a href="${api.data.user.profile_url}">${h(api.data.user.screen_name)}</a></b> s"""🔸<b><a href="${api.data.user.profile_url}">${h(api.data.user.screen_name)}</a></b>
| |
|${ch(api.data.text)}${parseMStatus_forPicPreview(api.data)} |${ch(api.data.text)}${parseMStatus_forPicPreview(api.data)}
|${parseMStatus_forRetweeted(api.data)} |${parseMStatus_forRetweeted(api.data)}
|<i><a href="${genWeiboStatusUrl(StatusUrlInfo(api.data.user.id.toString, api.data.id))}">${h(api.data.created_at)}</a></i>""".stripMargin |<i><a href="$statusUrl">${h(api.data.created_at)}</a></i>""".stripMargin
val title = api.data.text.ensureNotExceed(35) val title = api.data.text.ensureNotExceed(35)
val description: String = originUrl val description: String = originUrl
api.data.pics match api.data.pics match
case None => case None =>
SocialContent(title, description, content, content_withPicPlaceholder, Nil) SocialContent(title, description, content, content_withPicPlaceholder, Nil)
case Some(pics) => case Some(pics) =>
val mediaGroup = pics.map(f => SocialMediaWithBytesData(MApi.Fetch.pic(f.large.url))(Photo)) val mediaGroup = pics.map(f => SocialMediaWithBytesData(MApi.Fetch.pic(f.large.url))(Photo, statusUrl))
SocialContent( SocialContent(
if title.nonEmpty then title else if title.nonEmpty then title else
s"from ${api.data.user.screen_name}", s"from ${api.data.user.screen_name}",