mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-22 11:14:55 +08:00
make private url share can get from content
This commit is contained in:
parent
ad65ab7a73
commit
c4632263de
@ -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.3.0-dev14
|
||||
VERSION = 1.3.0-dev15
|
||||
|
||||
USE_DELTA = false
|
||||
VERSION_DELTA =
|
||||
|
@ -24,7 +24,7 @@ class GetSocial (using coeur: MornyCoeur) extends ITelegramCommand {
|
||||
|
||||
if command.args.length < 1 then { do404(); return }
|
||||
|
||||
if !OnGetSocial.tryFetchSocial(command.args(0))(using event.message.chat.id, event.message.messageId) then
|
||||
if !OnGetSocial.tryFetchSocial(Right(command.args(0)))(using event.message.chat.id, event.message.messageId) then
|
||||
do404()
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import cc.sukazyo.cono.morny.extra.{twitter, weibo}
|
||||
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec
|
||||
import cc.sukazyo.cono.morny.Log.{exceptionLog, logger}
|
||||
import cc.sukazyo.cono.morny.data.social.{SocialTwitterParser, SocialWeiboParser}
|
||||
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Message.entitiesSafe
|
||||
import com.pengrad.telegrambot.model.Chat
|
||||
import com.pengrad.telegrambot.model.request.ParseMode
|
||||
import com.pengrad.telegrambot.request.{SendMessage, SendSticker}
|
||||
@ -20,7 +21,11 @@ class OnGetSocial (using coeur: MornyCoeur) extends EventListener {
|
||||
if messageEvent.chat.`type` != Chat.Type.Private then return;
|
||||
if messageEvent.text == null then return;
|
||||
|
||||
if tryFetchSocial(messageEvent.text)(using messageEvent.chat.id, messageEvent.messageId) then
|
||||
if tryFetchSocial(
|
||||
Left((
|
||||
messageEvent.text :: messageEvent.entitiesSafe.map(f => f.url).filterNot(f => f == null)
|
||||
).mkString(" "))
|
||||
)(using messageEvent.chat.id, messageEvent.messageId) then
|
||||
event.setEventOk
|
||||
|
||||
}
|
||||
@ -31,63 +36,81 @@ object OnGetSocial {
|
||||
|
||||
/** Try fetch from url from input and output fetched social content.
|
||||
*
|
||||
* @param text input text, maybe a social url.
|
||||
* @param text input text, receive either a texts contains some URLs that should
|
||||
* pass through [[Left]], or a exactly URL that should pass through
|
||||
* [[Right]].
|
||||
* @param replyChat chat that should be output to.
|
||||
* @param replyToMessage message that should be reply to.
|
||||
* @param coeur [[MornyCoeur]] instance for executing Telegram function.
|
||||
* @return [[true]] if fetched social content and sent something out.
|
||||
*/
|
||||
def tryFetchSocial (text: String)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur): Boolean = {
|
||||
val _text = text.trim
|
||||
def tryFetchSocial (text: Either[String, String])(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur): Boolean = {
|
||||
|
||||
var succeed = 0
|
||||
|
||||
import io.circe.{DecodingFailure, ParsingFailure}
|
||||
import sttp.client3.{HttpError, SttpClientException}
|
||||
import twitter.{FXApi, TweetUrlInformation}
|
||||
import weibo.{MApi, StatusUrlInfo}
|
||||
twitter.parseTweetUrl(_text) match
|
||||
case None =>
|
||||
case Some(TweetUrlInformation(_, _, screenName, statusId, _, _)) =>
|
||||
succeed += 1
|
||||
try {
|
||||
val api = FXApi.Fetch.status(Some(screenName), statusId)
|
||||
SocialTwitterParser.parseFXTweet(api).outputToTelegram
|
||||
} catch case e: (SttpClientException | ParsingFailure | DecodingFailure) =>
|
||||
coeur.account exec SendSticker(
|
||||
replyChat,
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(replyToMessage)
|
||||
logger error
|
||||
"Error on requesting FixTweet API\n" + exceptionLog(e)
|
||||
coeur.daemons.reporter.exception(e, "Error on requesting FixTweet API")
|
||||
|
||||
weibo.parseWeiboStatusUrl(_text) match
|
||||
case None =>
|
||||
case Some(StatusUrlInfo(_, id)) =>
|
||||
succeed += 1
|
||||
try {
|
||||
val api = MApi.Fetch.statuses_show(id)
|
||||
SocialWeiboParser.parseMStatus(api).outputToTelegram
|
||||
} catch
|
||||
case e: HttpError[?] =>
|
||||
coeur.account exec SendMessage(
|
||||
replyChat,
|
||||
// language=html
|
||||
s"""Weibo Request Error <code>${e.statusCode}</code>
|
||||
|<pre><code>${e.body}</code></pre>""".stripMargin
|
||||
).replyToMessageId(replyToMessage).parseMode(ParseMode.HTML)
|
||||
case e: (SttpClientException | ParsingFailure | DecodingFailure) =>
|
||||
coeur.account exec SendSticker(
|
||||
replyChat,
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(replyToMessage)
|
||||
logger error
|
||||
"Error on requesting Weibo m.API\n" + exceptionLog(e)
|
||||
coeur.daemons.reporter.exception(e, "Error on requesting Weibo m.API")
|
||||
{
|
||||
text match
|
||||
case Left(texts) =>
|
||||
twitter.guessTweetUrl(texts.trim)
|
||||
case Right(url) =>
|
||||
twitter.parseTweetUrl(url.trim).toList
|
||||
}.map(f => {
|
||||
succeed += 1
|
||||
tryFetchSocialOfTweet(f)
|
||||
})
|
||||
|
||||
{
|
||||
text match
|
||||
case Left(texts) =>
|
||||
weibo.guessWeiboStatusUrl(texts.trim)
|
||||
case Right(url) =>
|
||||
weibo.parseWeiboStatusUrl(url.trim).toList
|
||||
}.map(f => {
|
||||
succeed += 1
|
||||
tryFetchSocialOfWeibo(f)
|
||||
})
|
||||
succeed > 0
|
||||
|
||||
}
|
||||
|
||||
def tryFetchSocialOfTweet (url: twitter.TweetUrlInformation)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) =
|
||||
import io.circe.{DecodingFailure, ParsingFailure}
|
||||
import sttp.client3.SttpClientException
|
||||
import twitter.FXApi
|
||||
try {
|
||||
val api = FXApi.Fetch.status(Some(url.screenName), url.statusId)
|
||||
SocialTwitterParser.parseFXTweet(api).outputToTelegram
|
||||
} catch case e: (SttpClientException | ParsingFailure | DecodingFailure) =>
|
||||
coeur.account exec SendSticker(
|
||||
replyChat,
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(replyToMessage)
|
||||
logger error
|
||||
"Error on requesting FixTweet API\n" + exceptionLog(e)
|
||||
coeur.daemons.reporter.exception(e, "Error on requesting FixTweet API")
|
||||
|
||||
def tryFetchSocialOfWeibo (url: weibo.StatusUrlInfo)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur) =
|
||||
import io.circe.{DecodingFailure, ParsingFailure}
|
||||
import sttp.client3.{HttpError, SttpClientException}
|
||||
import weibo.MApi
|
||||
try {
|
||||
val api = MApi.Fetch.statuses_show(url.id)
|
||||
SocialWeiboParser.parseMStatus(api).outputToTelegram
|
||||
} catch
|
||||
case e: HttpError[?] =>
|
||||
coeur.account exec SendMessage(
|
||||
replyChat,
|
||||
// language=html
|
||||
s"""Weibo Request Error <code>${e.statusCode}</code>
|
||||
|<pre><code>${e.body}</code></pre>""".stripMargin
|
||||
).replyToMessageId(replyToMessage).parseMode(ParseMode.HTML)
|
||||
case e: (SttpClientException | ParsingFailure | DecodingFailure) =>
|
||||
coeur.account exec SendSticker(
|
||||
replyChat,
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(replyToMessage)
|
||||
logger error
|
||||
"Error on requesting Weibo m.API\n" + exceptionLog(e)
|
||||
coeur.daemons.reporter.exception(e, "Error on requesting Weibo m.API")
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import scala.util.matching.Regex
|
||||
|
||||
package object twitter {
|
||||
|
||||
private val REGEX_TWEET_URL: Regex = "^(?:https?://)?((?:(?:(?:c\\.)?vx|fx|www\\.)?twitter|(?:www\\.|fixup|fixv)?x)\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(?:\\?([\\w&=-]+))?$"r
|
||||
private val REGEX_TWEET_URL: Regex = "(?:https?://)?((?:(?:(?:c\\.)?vx|fx|www\\.)?twitter|(?:www\\.|fixup|fixv)?x)\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(?:\\?(\\S+))?"r
|
||||
|
||||
/** Messages that can contains on a tweet url.
|
||||
*
|
||||
@ -69,4 +69,13 @@ package object twitter {
|
||||
))
|
||||
case _ => None
|
||||
|
||||
def guessTweetUrl (text: String): List[TweetUrlInformation] =
|
||||
REGEX_TWEET_URL.findAllMatchIn(text).map(f => {
|
||||
TweetUrlInformation(
|
||||
f.group(1), f.group(2), f.group(3), f.group(4),
|
||||
Option(f.group(5)),
|
||||
Option(f.group(6))
|
||||
)
|
||||
}).toList
|
||||
|
||||
}
|
||||
|
@ -23,13 +23,18 @@ package object weibo {
|
||||
// s"https://$cdn.singimg.cn/$mode/$pid.jpg"
|
||||
// }
|
||||
|
||||
private val REGEX_WEIBO_STATUS_URL = "^(?:https?://)?((?:www\\.|m.)?weibo\\.(?:com|cn))/(\\d+)/([0-9a-zA-Z]+)/?(?:\\?([\\w&=-]+))?$"r
|
||||
private val REGEX_WEIBO_STATUS_URL = "(?:https?://)?((?:www\\.|m.)?weibo\\.(?:com|cn))/(\\d+)/([0-9a-zA-Z]+)/?(?:\\?(\\S+))?"r
|
||||
|
||||
def parseWeiboStatusUrl (url: String): Option[StatusUrlInfo] =
|
||||
url match
|
||||
case REGEX_WEIBO_STATUS_URL(_, uid, id, _) => Some(StatusUrlInfo(uid, id))
|
||||
case _ => None
|
||||
|
||||
def guessWeiboStatusUrl (text: String): List[StatusUrlInfo] =
|
||||
REGEX_WEIBO_STATUS_URL.findAllMatchIn(text).map(matches => {
|
||||
StatusUrlInfo(matches.group(2), matches.group(3))
|
||||
}).toList
|
||||
|
||||
def genWeiboStatusUrl (url: StatusUrlInfo): String =
|
||||
s"https://weibo.com/${url.uid}/${url.id}"
|
||||
|
||||
|
@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny.util.tgapi
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException
|
||||
import com.pengrad.telegrambot.TelegramBot
|
||||
import com.pengrad.telegrambot.model.{Chat, ChatMember, User}
|
||||
import com.pengrad.telegrambot.model.*
|
||||
import com.pengrad.telegrambot.request.{BaseRequest, GetChatMember}
|
||||
import com.pengrad.telegrambot.response.BaseResponse
|
||||
|
||||
@ -66,6 +66,14 @@ object TelegramExtensions {
|
||||
|
||||
}}
|
||||
|
||||
object Message { extension (self: Message) {
|
||||
|
||||
def entitiesSafe: List[MessageEntity] =
|
||||
if self.entities == null then Nil else
|
||||
self.entities.toList
|
||||
|
||||
}}
|
||||
|
||||
class LimboUser (id: Long) extends User(id)
|
||||
class LimboChat (val _id: Long) extends Chat() {
|
||||
override val id: java.lang.Long = _id
|
||||
|
@ -3,7 +3,6 @@ package cc.sukazyo.cono.morny.test.extra
|
||||
import cc.sukazyo.cono.morny.extra.BilibiliForms.*
|
||||
import cc.sukazyo.cono.morny.test.MornyTests
|
||||
import org.scalatest.prop.TableDrivenPropertyChecks
|
||||
import org.scalatest.tagobjects.{Network, Slow}
|
||||
|
||||
class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks {
|
||||
|
||||
@ -89,32 +88,34 @@ class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks {
|
||||
|
||||
}
|
||||
|
||||
"while destruct b23.tv share link :" - {
|
||||
|
||||
val examples = Table(
|
||||
("b23_link", "bilibili_video_link"),
|
||||
("https://b23.tv/iiCldvZ", "https://www.bilibili.com/video/BV1Gh411P7Sh?buvid=XY6F25B69BE9CF469FF5B917D012C93E95E72&is_story_h5=false&mid=wD6DQnYivIG5pfA3sAGL6A%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=android&share_plat=android&share_session_id=8081015b-1210-4dea-a665-6746b4850fcd&share_source=COPY&share_tag=s_i×tamp=1689605644&unique_k=iiCldvZ&up_id=19977489"),
|
||||
("https://b23.tv/xWiWFl9", "https://www.bilibili.com/video/BV1N54y1c7us?buvid=XY705C970C2ADBB710C1801E1F45BDC3B9210&is_story_h5=false&mid=w%2B1u1wpibjYsW4pP%2FIo7Ww%3D%3D&p=1&plat_id=116&share_from=ugc&share_medium=android&share_plat=android&share_session_id=6da09711-d601-4da4-bba1-46a4edbb1c60&share_source=COPY&share_tag=s_i×tamp=1680280016&unique_k=xWiWFl9&up_id=275354674"),
|
||||
("http://b23.tv/uJPIvhv", "https://www.bilibili.com/video/BV1E84y1C7in?is_story_h5=false&p=1&share_from=ugc&share_medium=android&share_plat=android&share_session_id=4a077fa1-5ee2-40d4-ac37-bf9a2bf567e3&share_source=COPY&share_tag=s_i×tamp=1669044671&unique_k=uJPIvhv")
|
||||
// this link have been expired
|
||||
// ("http://b23.tv/3ymowwx", "https://www.bilibili.com/video/BV15Y411n754?p=1&share_medium=android_i&share_plat=android&share_source=COPY&share_tag=s_i×tamp=1650293889&unique_k=3ymowwx")
|
||||
)
|
||||
|
||||
"not b23.tv link is not supported" in:
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("sukazyo.cc/2xhUHO2e")
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://sukazyo.cc/2xhUHO2e")
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("长月烬明澹台烬心理分析向解析(一)因果之锁,渡魔之路")
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tvb/JDo2eaD")
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://ab23.tv/JDo2eaD")
|
||||
"b23.tv/avXXX video link is not supported" in:
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/av123456")
|
||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/BV1Q541167Qg")
|
||||
|
||||
forAll (examples) { (origin, result) =>
|
||||
s"b23 link $origin should be destructed to $result" taggedAs (Slow, Network) in:
|
||||
destructB23Url(origin) shouldEqual result
|
||||
}
|
||||
|
||||
}
|
||||
// Due to this url is expirable, I have no energy to update links in time.
|
||||
// So I decide to deprecate the tests.
|
||||
// "while destruct b23.tv share link :" - {
|
||||
//
|
||||
// val examples = Table(
|
||||
// ("b23_link", "bilibili_video_link"),
|
||||
// ("https://b23.tv/iiCldvZ", "https://www.bilibili.com/video/BV1Gh411P7Sh?buvid=XY6F25B69BE9CF469FF5B917D012C93E95E72&is_story_h5=false&mid=wD6DQnYivIG5pfA3sAGL6A%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=android&share_plat=android&share_session_id=8081015b-1210-4dea-a665-6746b4850fcd&share_source=COPY&share_tag=s_i×tamp=1689605644&unique_k=iiCldvZ&up_id=19977489"),
|
||||
// ("https://b23.tv/xWiWFl9", "https://www.bilibili.com/video/BV1N54y1c7us?buvid=XY705C970C2ADBB710C1801E1F45BDC3B9210&is_story_h5=false&mid=w%2B1u1wpibjYsW4pP%2FIo7Ww%3D%3D&p=1&plat_id=116&share_from=ugc&share_medium=android&share_plat=android&share_session_id=6da09711-d601-4da4-bba1-46a4edbb1c60&share_source=COPY&share_tag=s_i×tamp=1680280016&unique_k=xWiWFl9&up_id=275354674"),
|
||||
// ("http://b23.tv/uJPIvhv", "https://www.bilibili.com/video/BV1E84y1C7in?is_story_h5=false&p=1&share_from=ugc&share_medium=android&share_plat=android&share_session_id=4a077fa1-5ee2-40d4-ac37-bf9a2bf567e3&share_source=COPY&share_tag=s_i×tamp=1669044671&unique_k=uJPIvhv")
|
||||
// // this link have been expired
|
||||
//// ("http://b23.tv/3ymowwx", "https://www.bilibili.com/video/BV15Y411n754?p=1&share_medium=android_i&share_plat=android&share_source=COPY&share_tag=s_i×tamp=1650293889&unique_k=3ymowwx")
|
||||
// )
|
||||
//
|
||||
// "not b23.tv link is not supported" in:
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("sukazyo.cc/2xhUHO2e")
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://sukazyo.cc/2xhUHO2e")
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("长月烬明澹台烬心理分析向解析(一)因果之锁,渡魔之路")
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tvb/JDo2eaD")
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://ab23.tv/JDo2eaD")
|
||||
// "b23.tv/avXXX video link is not supported" in:
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/av123456")
|
||||
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/BV1Q541167Qg")
|
||||
//
|
||||
// forAll (examples) { (origin, result) =>
|
||||
// s"b23 link $origin should be destructed to $result" taggedAs (Slow, Network) in:
|
||||
// destructB23Url(origin) shouldEqual result
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user