feat: support parse github repo(project)
This commit is contained in:
15 files changed
+269
-55
No files matched your search
BIN
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
@@ -26,7 +26,8 @@ val DEFAULT_CONFIG = Config(
|
|||||||
accessToken = "114514",
|
accessToken = "114514",
|
||||||
port = 6760,
|
port = 6760,
|
||||||
listeningGroups = listOf(114514, 1919810),
|
listeningGroups = listOf(114514, 1919810),
|
||||||
qweatherKey = "114514"
|
qweatherKey = "114514",
|
||||||
|
githubKey = "1919810"
|
||||||
)
|
)
|
||||||
|
|
||||||
val ADMINS = listOf(
|
val ADMINS = listOf(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ package cn.rtast.fancybot
|
|||||||
|
|
||||||
import cn.rtast.fancybot.commands.*
|
import cn.rtast.fancybot.commands.*
|
||||||
import cn.rtast.fancybot.commands.misc.BVParseCommand
|
import cn.rtast.fancybot.commands.misc.BVParseCommand
|
||||||
|
import cn.rtast.fancybot.commands.misc.GitHubParseCommand
|
||||||
import cn.rtast.fancybot.commands.misc.ImageURLCommand
|
import cn.rtast.fancybot.commands.misc.ImageURLCommand
|
||||||
import cn.rtast.fancybot.commands.misc.ReverseGIFCommand
|
import cn.rtast.fancybot.commands.misc.ReverseGIFCommand
|
||||||
import cn.rtast.fancybot.entity.bili.CardShare
|
import cn.rtast.fancybot.entity.bili.CardShare
|
||||||
@@ -38,6 +39,14 @@ class FancyBot : OBMessage {
|
|||||||
val msg = message.rawMessage
|
val msg = message.rawMessage
|
||||||
val groupId = message.groupId
|
val groupId = message.groupId
|
||||||
println("$sender($senderId: $groupId): $msg")
|
println("$sender($senderId: $groupId): $msg")
|
||||||
|
|
||||||
|
if (message.rawMessage.startsWith("https://github.com/") ||
|
||||||
|
message.rawMessage.startsWith("git@github.com:") ||
|
||||||
|
message.rawMessage.split("/").size == 2
|
||||||
|
) {
|
||||||
|
GitHubParseCommand.parse(this, message)
|
||||||
|
}
|
||||||
|
|
||||||
if (message.rawMessage.startsWith("BV") ||
|
if (message.rawMessage.startsWith("BV") ||
|
||||||
message.rawMessage.startsWith("https://www.bilibili.com") ||
|
message.rawMessage.startsWith("https://www.bilibili.com") ||
|
||||||
message.rawMessage.contains("https://b23.tv/") ||
|
message.rawMessage.contains("https://b23.tv/") ||
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ package cn.rtast.fancybot.commands.misc
|
|||||||
import cn.rtast.fancybot.entity.bili.BVID
|
import cn.rtast.fancybot.entity.bili.BVID
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.Resources
|
import cn.rtast.fancybot.util.Resources
|
||||||
|
import cn.rtast.fancybot.util.drawCustomImage
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.setTruncat
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import cn.rtast.rob.util.ob.MessageChain
|
||||||
import cn.rtast.rob.util.ob.OBMessage
|
import cn.rtast.rob.util.ob.OBMessage
|
||||||
@@ -18,8 +20,6 @@ import okhttp3.OkHttpClient
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.Graphics2D
|
|
||||||
import java.awt.geom.RoundRectangle2D
|
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
@@ -59,35 +59,6 @@ object BVParseCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawImage(
|
|
||||||
image: BufferedImage,
|
|
||||||
g2d: Graphics2D,
|
|
||||||
x: Int,
|
|
||||||
y: Int,
|
|
||||||
maxWidth: Double,
|
|
||||||
maxHeight: Double,
|
|
||||||
clip: Boolean
|
|
||||||
) {
|
|
||||||
val originalWidth = image.getWidth(null)
|
|
||||||
val originalHeight = image.getHeight(null)
|
|
||||||
val widthScale = maxWidth / originalWidth
|
|
||||||
val heightScale = maxHeight / originalHeight
|
|
||||||
val scale = minOf(widthScale, heightScale)
|
|
||||||
val targetWidth = (originalWidth * scale).toInt()
|
|
||||||
val targetHeight = (originalHeight * scale).toInt()
|
|
||||||
if (clip) {
|
|
||||||
g2d.clip = RoundRectangle2D.Float(
|
|
||||||
x.toFloat(),
|
|
||||||
y.toFloat(),
|
|
||||||
targetWidth.toFloat(),
|
|
||||||
targetHeight.toFloat(),
|
|
||||||
30.toFloat(),
|
|
||||||
30.toFloat()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
g2d.drawImage(image, x, y, targetWidth, targetHeight, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createResponseImage(
|
private fun createResponseImage(
|
||||||
title: String,
|
title: String,
|
||||||
author: String,
|
author: String,
|
||||||
@@ -119,35 +90,24 @@ object BVParseCommand {
|
|||||||
g2d.drawString(reply, 300, 290)
|
g2d.drawString(reply, 300, 290)
|
||||||
g2d.drawString(share, 300, 200)
|
g2d.drawString(share, 300, 200)
|
||||||
// draw video title
|
// draw video title
|
||||||
val maxWidth = 500
|
val truncatedText = setTruncat(title, g2d)
|
||||||
val fontMetrics = g2d.fontMetrics
|
|
||||||
val textWidth = fontMetrics.stringWidth(title)
|
|
||||||
val truncatedText = if (textWidth > maxWidth) {
|
|
||||||
val ellipsisWidth = fontMetrics.stringWidth("...")
|
|
||||||
val width = maxWidth - ellipsisWidth
|
|
||||||
var endIndex = title.length
|
|
||||||
while (fontMetrics.stringWidth(title.substring(0, endIndex)) > width && endIndex > 0) {
|
|
||||||
endIndex--
|
|
||||||
}
|
|
||||||
title.substring(0, endIndex) + "..."
|
|
||||||
} else title
|
|
||||||
g2d.font = titleFont
|
g2d.font = titleFont
|
||||||
g2d.drawString(truncatedText, 20, 70)
|
g2d.drawString(truncatedText, 20, 70)
|
||||||
// draw author name
|
// draw author name
|
||||||
g2d.drawString(author, 40, 580)
|
g2d.drawString(author, 40, 580)
|
||||||
// draw icons
|
// draw icons
|
||||||
this.drawImage(favoriteIcon, g2d, 230, 340, 50.0, 50.0, false)
|
g2d.drawCustomImage(favoriteIcon, 230, 340, 50.0, 50.0, false)
|
||||||
this.drawImage(replyIcon, g2d, 230, 250, 50.0, 50.0, false)
|
g2d.drawCustomImage(replyIcon, 230, 250, 50.0, 50.0, false)
|
||||||
this.drawImage(shareIcon, g2d, 230, 160, 50.0, 50.0, false)
|
g2d.drawCustomImage(shareIcon, 230, 160, 50.0, 50.0, false)
|
||||||
this.drawImage(viewIcon, g2d, 40, 340, 50.0, 50.0, false)
|
g2d.drawCustomImage(viewIcon, 40, 340, 50.0, 50.0, false)
|
||||||
this.drawImage(coinIcon, g2d, 40, 250, 50.0, 50.0, false)
|
g2d.drawCustomImage(coinIcon, 40, 250, 50.0, 50.0, false)
|
||||||
this.drawImage(likeIcon, g2d, 40, 160, 50.0, 50.0, false)
|
g2d.drawCustomImage(likeIcon, 40, 160, 50.0, 50.0, false)
|
||||||
// draw 22 logo
|
// draw 22 logo
|
||||||
this.drawImage(twoTwoLogo, g2d, 800, 450, 90.0, 160.0, false)
|
g2d.drawCustomImage(twoTwoLogo, 800, 450, 90.0, 160.0, false)
|
||||||
// draw author face
|
// draw author face
|
||||||
this.drawImage(faceImage, g2d, 40, 480, 60.0, 60.0, true)
|
g2d.drawCustomImage(faceImage, 40, 480, 60.0, 60.0, true)
|
||||||
// draw cover image
|
// draw cover image
|
||||||
this.drawImage(coverImage, g2d, 430, 140, 600.0, 300.0, true)
|
g2d.drawCustomImage(coverImage, 430, 140, 600.0, 300.0, true)
|
||||||
g2d.dispose()
|
g2d.dispose()
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
ImageIO.write(backgroundImage, "png", byteArrayOutputStream)
|
ImageIO.write(backgroundImage, "png", byteArrayOutputStream)
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/12
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.github.RepoInfo
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.Resources
|
||||||
|
import cn.rtast.fancybot.util.drawCustomImage
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.setTruncat
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.ob.MessageChain
|
||||||
|
import cn.rtast.rob.util.ob.OBMessage
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.net.URI
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
object GitHubParseCommand {
|
||||||
|
|
||||||
|
private const val REPO_INFO_API = "https://api.github.com/repos"
|
||||||
|
private const val CANVAS_WIDTH = 1620
|
||||||
|
private const val CANVAS_HEIGHT = 1000
|
||||||
|
private val githubLogo = ImageIO.read(Resources.loadFromResources("github/favicon.png"))
|
||||||
|
private val starIcon = ImageIO.read(Resources.loadFromResources("github/star.png"))
|
||||||
|
private val issueIcon = ImageIO.read(Resources.loadFromResources("github/issue.png"))
|
||||||
|
private val forkIcon = ImageIO.read(Resources.loadFromResources("github/fork.png"))
|
||||||
|
private val customFont = Font("Serif", Font.ITALIC, 50).deriveFont(Font.ITALIC).deriveFont(Font.BOLD)
|
||||||
|
private val titleCustomFont = Font("Serif", Font.ITALIC, 75).deriveFont(Font.ITALIC).deriveFont(Font.BOLD)
|
||||||
|
private val descriptionCustomFont = Font("Serif", Font.ITALIC, 50).deriveFont(Font.ITALIC).deriveFont(Font.BOLD)
|
||||||
|
|
||||||
|
private val languageColors = mapOf(
|
||||||
|
"Kotlin" to Color(169, 123, 255),
|
||||||
|
"Java" to Color(176, 114, 25),
|
||||||
|
"Python" to Color(53, 114, 165),
|
||||||
|
"JavaScript" to Color(241, 224, 90),
|
||||||
|
"C++" to Color(243, 75, 125),
|
||||||
|
"Go" to Color(0, 173, 216),
|
||||||
|
"Ruby" to Color(112, 21, 22),
|
||||||
|
"PHP" to Color(79, 93, 149),
|
||||||
|
"TypeScript" to Color(43, 116, 137),
|
||||||
|
"Swift" to Color(240, 81, 56),
|
||||||
|
"Unknown" to Color(211, 211, 211)
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Int.formatNumber(): String {
|
||||||
|
return when {
|
||||||
|
this >= 1_000_000 -> String.format("%.1fM", this / 1_000_000.0)
|
||||||
|
this >= 10_000 -> String.format("%.1fk", this / 1_000.0)
|
||||||
|
this >= 1_000 -> String.format("%dk", this / 1_000)
|
||||||
|
else -> this.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLanguageColor(language: String): Color {
|
||||||
|
return languageColors[language] ?: languageColors["Unknown"]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRepoStat(username: String, repo: String): RepoInfo {
|
||||||
|
return Http.get<RepoInfo>(
|
||||||
|
"$REPO_INFO_API/$username/$repo",
|
||||||
|
headers = mapOf("Authorization" to "Bearer ${configManager.githubKey}")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createImage(repoStat: RepoInfo): String {
|
||||||
|
val canvas = BufferedImage(CANVAS_WIDTH, CANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB)
|
||||||
|
val g2d = canvas.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.font = customFont
|
||||||
|
g2d.color = Color.WHITE
|
||||||
|
g2d.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
|
||||||
|
g2d.color = this.getLanguageColor(repoStat.language)
|
||||||
|
g2d.fillRect(0, CANVAS_HEIGHT - 20, CANVAS_WIDTH, 20)
|
||||||
|
g2d.drawCustomImage(githubLogo, 1300, 780, 100.0, 100.0, false) // draw github logo
|
||||||
|
g2d.drawCustomImage(starIcon, 100, 730, 70.0, 70.0, false) // draw star icon
|
||||||
|
g2d.drawCustomImage(issueIcon, 500, 730, 70.0, 70.0, false) // draw issue icon
|
||||||
|
g2d.drawCustomImage(forkIcon, 900, 730, 70.0, 70.0, false) // draw fork icon
|
||||||
|
g2d.color = Color(60, 60, 60)
|
||||||
|
g2d.drawString("Stars", 160, 840)
|
||||||
|
g2d.drawString("Issues", 560, 840)
|
||||||
|
g2d.drawString("Forks", 960, 840)
|
||||||
|
g2d.drawString(repoStat.starsCount.formatNumber(), 200, 780)
|
||||||
|
g2d.drawString(repoStat.openIssueCount.formatNumber(), 600, 780)
|
||||||
|
g2d.drawString(repoStat.forksCount.formatNumber(), 1000, 780)
|
||||||
|
g2d.font = titleCustomFont
|
||||||
|
val truncatedFullNameText = setTruncat(repoStat.fullName, g2d, 1000)
|
||||||
|
g2d.drawString(truncatedFullNameText, 80, 280)
|
||||||
|
g2d.font = descriptionCustomFont
|
||||||
|
val truncatedDescription = setTruncat(repoStat.description, g2d, 1000)
|
||||||
|
g2d.drawString(truncatedDescription, 20, 450)
|
||||||
|
val avatarImage = ImageIO.read(URI(repoStat.owner.avatarUrl).toURL())
|
||||||
|
g2d.drawCustomImage(avatarImage, 1200, 300, 300.0, 300.0, true)
|
||||||
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
|
ImageIO.write(canvas, "png", byteArrayOutputStream)
|
||||||
|
val imageBytes = byteArrayOutputStream.toByteArray()
|
||||||
|
return imageBytes.encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun parse(listener: OBMessage, message: GroupMessage) {
|
||||||
|
val path = message.rawMessage
|
||||||
|
.replace(".git", "")
|
||||||
|
.replace("https://github.com/", "")
|
||||||
|
.replace("git@github.com:", "")
|
||||||
|
.split("/")
|
||||||
|
val user = path.first()
|
||||||
|
val repo = path.last()
|
||||||
|
val repoStat = this.getRepoStat(user, repo)
|
||||||
|
val image = this.createImage(repoStat)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addReply(message.messageId)
|
||||||
|
.addImage(image, true)
|
||||||
|
.build()
|
||||||
|
listener.sendGroupMessage(message.groupId, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,5 +16,6 @@ data class Config(
|
|||||||
val accessToken: String,
|
val accessToken: String,
|
||||||
val port: Int,
|
val port: Int,
|
||||||
val listeningGroups: List<Long>,
|
val listeningGroups: List<Long>,
|
||||||
val qweatherKey: String
|
val qweatherKey: String,
|
||||||
|
val githubKey: String,
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/12
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.entity.github
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RepoInfo(
|
||||||
|
val owner: Owner,
|
||||||
|
@SerializedName("full_name")
|
||||||
|
val fullName: String,
|
||||||
|
val description: String,
|
||||||
|
@SerializedName("forks_count")
|
||||||
|
val forksCount: Int,
|
||||||
|
val language: String,
|
||||||
|
@SerializedName("stargazers_count")
|
||||||
|
val starsCount: Int,
|
||||||
|
@SerializedName("open_issues_count")
|
||||||
|
val openIssueCount: Int
|
||||||
|
) {
|
||||||
|
data class Owner(
|
||||||
|
@SerializedName("avatar_url")
|
||||||
|
val avatarUrl: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/12
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.util
|
||||||
|
|
||||||
|
import java.awt.Graphics2D
|
||||||
|
import java.awt.geom.RoundRectangle2D
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
fun Graphics2D.drawCustomImage(
|
||||||
|
image: BufferedImage,
|
||||||
|
x: Int,
|
||||||
|
y: Int,
|
||||||
|
maxWidth: Double,
|
||||||
|
maxHeight: Double,
|
||||||
|
clip: Boolean
|
||||||
|
) {
|
||||||
|
val originalWidth = image.getWidth(null)
|
||||||
|
val originalHeight = image.getHeight(null)
|
||||||
|
val widthScale = maxWidth / originalWidth
|
||||||
|
val heightScale = maxHeight / originalHeight
|
||||||
|
val scale = minOf(widthScale, heightScale)
|
||||||
|
val targetWidth = (originalWidth * scale).toInt()
|
||||||
|
val targetHeight = (originalHeight * scale).toInt()
|
||||||
|
if (clip) {
|
||||||
|
this.clip = RoundRectangle2D.Float(
|
||||||
|
x.toFloat(),
|
||||||
|
y.toFloat(),
|
||||||
|
targetWidth.toFloat(),
|
||||||
|
targetHeight.toFloat(),
|
||||||
|
30.toFloat(),
|
||||||
|
30.toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
this.drawImage(image, x, y, targetWidth, targetHeight, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BufferedImage.scaleImage(size: Pair<Int, Int>): BufferedImage {
|
||||||
|
val scaledImage = BufferedImage(size.first, size.second, this.type)
|
||||||
|
val graphics2d = scaledImage.createGraphics()
|
||||||
|
graphics2d.drawImage(this, 0, 0, size.first, size.second, null)
|
||||||
|
graphics2d.dispose()
|
||||||
|
return scaledImage
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.toBufferedImage(): BufferedImage {
|
||||||
|
ByteArrayInputStream(this).use { inputStream ->
|
||||||
|
return ImageIO.read(inputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BufferedImage.toByteArray(): ByteArray {
|
||||||
|
ByteArrayOutputStream().use { outputStream ->
|
||||||
|
ImageIO.write(this, "png", outputStream)
|
||||||
|
return outputStream.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,4 +18,5 @@ class ConfigManager : JsonFileHandler<Config>("config.json") {
|
|||||||
val wsType get() = this.read<Config>().wsType
|
val wsType get() = this.read<Config>().wsType
|
||||||
val listeningGroups get() = this.read<Config>().listeningGroups
|
val listeningGroups get() = this.read<Config>().listeningGroups
|
||||||
val qweatherKey get() = this.read<Config>().qweatherKey
|
val qweatherKey get() = this.read<Config>().qweatherKey
|
||||||
|
val githubKey get() = this.read<Config>().githubKey
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/12
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.util.str
|
||||||
|
|
||||||
|
import java.awt.Graphics2D
|
||||||
|
|
||||||
|
fun setTruncat(origin: String, g2d: Graphics2D, maxWidth: Int = 500): String {
|
||||||
|
val fontMetrics = g2d.fontMetrics
|
||||||
|
val textWidth = fontMetrics.stringWidth(origin)
|
||||||
|
return if (textWidth > maxWidth) {
|
||||||
|
val ellipsisWidth = fontMetrics.stringWidth("...")
|
||||||
|
val width = maxWidth - ellipsisWidth
|
||||||
|
var endIndex = origin.length
|
||||||
|
while (fontMetrics.stringWidth(origin.substring(0, endIndex)) > width && endIndex > 0) {
|
||||||
|
endIndex--
|
||||||
|
}
|
||||||
|
origin.substring(0, endIndex) + "..."
|
||||||
|
} else origin
|
||||||
|
}
|
||||||
@@ -9,5 +9,5 @@
|
|||||||
1919810
|
1919810
|
||||||
],
|
],
|
||||||
"qweatherKey": "114514",
|
"qweatherKey": "114514",
|
||||||
"qweatherPlan": "Free"
|
"githubKey": "1919810"
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Reference in New Issue
Block a user