mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2025-01-19 07:22:25 +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_CODE_STORE = https://github.com/Eyre-S/Coeur-Morny-Cono
|
||||||
MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s
|
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
|
USE_DELTA = false
|
||||||
VERSION_DELTA =
|
VERSION_DELTA =
|
||||||
|
@ -24,7 +24,7 @@ class GetSocial (using coeur: MornyCoeur) extends ITelegramCommand {
|
|||||||
|
|
||||||
if command.args.length < 1 then { do404(); return }
|
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()
|
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.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.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, SendSticker}
|
||||||
@ -20,7 +21,11 @@ class OnGetSocial (using coeur: MornyCoeur) extends EventListener {
|
|||||||
if messageEvent.chat.`type` != Chat.Type.Private then return;
|
if messageEvent.chat.`type` != Chat.Type.Private then return;
|
||||||
if messageEvent.text == null 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
|
event.setEventOk
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -31,63 +36,81 @@ object OnGetSocial {
|
|||||||
|
|
||||||
/** Try fetch from url from input and output fetched social content.
|
/** 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 replyChat chat that should be output to.
|
||||||
* @param replyToMessage message that should be reply to.
|
* @param replyToMessage message that should be reply to.
|
||||||
* @param coeur [[MornyCoeur]] instance for executing Telegram function.
|
* @param coeur [[MornyCoeur]] instance for executing Telegram function.
|
||||||
* @return [[true]] if fetched social content and sent something out.
|
* @return [[true]] if fetched social content and sent something out.
|
||||||
*/
|
*/
|
||||||
def tryFetchSocial (text: String)(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur): Boolean = {
|
def tryFetchSocial (text: Either[String, String])(using replyChat: Long, replyToMessage: Int)(using coeur: MornyCoeur): Boolean = {
|
||||||
val _text = text.trim
|
|
||||||
|
|
||||||
var succeed = 0
|
var succeed = 0
|
||||||
|
|
||||||
import io.circe.{DecodingFailure, ParsingFailure}
|
{
|
||||||
import sttp.client3.{HttpError, SttpClientException}
|
text match
|
||||||
import twitter.{FXApi, TweetUrlInformation}
|
case Left(texts) =>
|
||||||
import weibo.{MApi, StatusUrlInfo}
|
twitter.guessTweetUrl(texts.trim)
|
||||||
twitter.parseTweetUrl(_text) match
|
case Right(url) =>
|
||||||
case None =>
|
twitter.parseTweetUrl(url.trim).toList
|
||||||
case Some(TweetUrlInformation(_, _, screenName, statusId, _, _)) =>
|
}.map(f => {
|
||||||
succeed += 1
|
succeed += 1
|
||||||
try {
|
tryFetchSocialOfTweet(f)
|
||||||
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) =>
|
||||||
|
weibo.guessWeiboStatusUrl(texts.trim)
|
||||||
|
case Right(url) =>
|
||||||
|
weibo.parseWeiboStatusUrl(url.trim).toList
|
||||||
|
}.map(f => {
|
||||||
|
succeed += 1
|
||||||
|
tryFetchSocialOfWeibo(f)
|
||||||
|
})
|
||||||
succeed > 0
|
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 {
|
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.
|
/** Messages that can contains on a tweet url.
|
||||||
*
|
*
|
||||||
@ -69,4 +69,13 @@ package object twitter {
|
|||||||
))
|
))
|
||||||
case _ => None
|
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"
|
// 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] =
|
def parseWeiboStatusUrl (url: String): Option[StatusUrlInfo] =
|
||||||
url match
|
url match
|
||||||
case REGEX_WEIBO_STATUS_URL(_, uid, id, _) => Some(StatusUrlInfo(uid, id))
|
case REGEX_WEIBO_STATUS_URL(_, uid, id, _) => Some(StatusUrlInfo(uid, id))
|
||||||
case _ => None
|
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 =
|
def genWeiboStatusUrl (url: StatusUrlInfo): String =
|
||||||
s"https://weibo.com/${url.uid}/${url.id}"
|
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 cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException
|
||||||
import com.pengrad.telegrambot.TelegramBot
|
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.request.{BaseRequest, GetChatMember}
|
||||||
import com.pengrad.telegrambot.response.BaseResponse
|
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 LimboUser (id: Long) extends User(id)
|
||||||
class LimboChat (val _id: Long) extends Chat() {
|
class LimboChat (val _id: Long) extends Chat() {
|
||||||
override val id: java.lang.Long = _id
|
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.extra.BilibiliForms.*
|
||||||
import cc.sukazyo.cono.morny.test.MornyTests
|
import cc.sukazyo.cono.morny.test.MornyTests
|
||||||
import org.scalatest.prop.TableDrivenPropertyChecks
|
import org.scalatest.prop.TableDrivenPropertyChecks
|
||||||
import org.scalatest.tagobjects.{Network, Slow}
|
|
||||||
|
|
||||||
class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks {
|
class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks {
|
||||||
|
|
||||||
@ -89,32 +88,34 @@ class BilibiliFormsTest extends MornyTests with TableDrivenPropertyChecks {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"while destruct b23.tv share link :" - {
|
// Due to this url is expirable, I have no energy to update links in time.
|
||||||
|
// So I decide to deprecate the tests.
|
||||||
val examples = Table(
|
// "while destruct b23.tv share link :" - {
|
||||||
("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"),
|
// val examples = Table(
|
||||||
("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"),
|
// ("b23_link", "bilibili_video_link"),
|
||||||
("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")
|
// ("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"),
|
||||||
// this link have been expired
|
// ("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/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")
|
// ("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")
|
// "not b23.tv link is not supported" in:
|
||||||
an[IllegalArgumentException] should be thrownBy destructB23Url("长月烬明澹台烬心理分析向解析(一)因果之锁,渡魔之路")
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("sukazyo.cc/2xhUHO2e")
|
||||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tvb/JDo2eaD")
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://sukazyo.cc/2xhUHO2e")
|
||||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://ab23.tv/JDo2eaD")
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("长月烬明澹台烬心理分析向解析(一)因果之锁,渡魔之路")
|
||||||
"b23.tv/avXXX video link is not supported" in:
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tvb/JDo2eaD")
|
||||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/av123456")
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://ab23.tv/JDo2eaD")
|
||||||
an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/BV1Q541167Qg")
|
// "b23.tv/avXXX video link is not supported" in:
|
||||||
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/av123456")
|
||||||
forAll (examples) { (origin, result) =>
|
// an[IllegalArgumentException] should be thrownBy destructB23Url("https://b23.tv/BV1Q541167Qg")
|
||||||
s"b23 link $origin should be destructed to $result" taggedAs (Slow, Network) in:
|
//
|
||||||
destructB23Url(origin) shouldEqual result
|
// 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