From fdaa201f7ae8415a0ebcbc63f651ab01ced0235a Mon Sep 17 00:00:00 2001 From: shitlime Date: Wed, 31 Jul 2024 17:28:22 +0800 Subject: [PATCH 1/6] chore: update ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a65d6f2..379ee15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,8 +37,8 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: era.JAR - path: build/libs/*.jar + name: era.zip + path: build/libs # NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html). # If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version. From 2a4a009a18c3faa9be4274ec64dc2bee5f3212b3 Mon Sep 17 00:00:00 2001 From: shitlime Date: Fri, 6 Sep 2024 00:46:23 +0800 Subject: [PATCH 2/6] feat: auto get Bilibili vedio info --- .../shitlime/era/plugins/BilibiliPlugin.java | 48 ++++++ .../shitlime/era/service/BilibiliService.java | 137 ++++++++++++++++++ .../com/shitlime/era/utils/FileUtils.java | 38 ++++- src/main/resources/application.yml | 1 + 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java create mode 100644 src/main/java/com/shitlime/era/service/BilibiliService.java diff --git a/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java b/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java new file mode 100644 index 0000000..292a9ce --- /dev/null +++ b/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java @@ -0,0 +1,48 @@ +package com.shitlime.era.plugins; + +import com.mikuac.shiro.annotation.common.Shiro; +import com.mikuac.shiro.common.utils.ArrayMsgUtils; +import com.mikuac.shiro.core.Bot; +import com.mikuac.shiro.core.BotPlugin; +import com.mikuac.shiro.dto.event.message.AnyMessageEvent; +import com.mikuac.shiro.model.ArrayMsg; +import com.shitlime.era.service.BilibiliService; +import com.shitlime.era.utils.EraBotUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +@Shiro +@Component +public class BilibiliPlugin extends BotPlugin { + @Autowired + BilibiliService bilibiliService; + + @Override + public int onAnyMessage(Bot bot, AnyMessageEvent event) { + if (event.getArrayMsg().stream().anyMatch(m -> + m.getData().get("text").matches(".*BV[0-9a-zA-Z]{10}.*"))) { + // 识别到BV号自动发送视屏基本信息 + String msgPlain = EraBotUtils.getMsgPlain(event.getArrayMsg()); + Pattern pattern = Pattern.compile("BV[0-9a-zA-Z]{10}", Pattern.MULTILINE); + Matcher matcher = pattern.matcher(msgPlain); + if (matcher.find()) { + String bvid = matcher.group(); + log.info("获取Bilibili视频信息:" + bvid); + List msgList = bilibiliService.autoGetVideoInfo(bvid); + bot.sendMsg(event, msgList, true); + // 如果消息不只有BV号,发送纯BV号 + if (msgPlain.trim().equals(bvid)) { + bot.sendMsg(event, ArrayMsgUtils.builder().text(bvid).build(), true); + } + return MESSAGE_BLOCK; + } + } + return MESSAGE_IGNORE; + } +} diff --git a/src/main/java/com/shitlime/era/service/BilibiliService.java b/src/main/java/com/shitlime/era/service/BilibiliService.java new file mode 100644 index 0000000..efa96bf --- /dev/null +++ b/src/main/java/com/shitlime/era/service/BilibiliService.java @@ -0,0 +1,137 @@ +package com.shitlime.era.service; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.mikuac.shiro.common.utils.ArrayMsgUtils; +import com.mikuac.shiro.model.ArrayMsg; +import com.shitlime.era.utils.FileUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static java.lang.Math.min; + +@Slf4j +@Service +public class BilibiliService { + /** + * 自动返回视屏基本信息 + * + * @return + */ + public List autoGetVideoInfo(String videoId) { + String videoInfoJson = getVideoInfoJson(videoId); + JSONObject jsonObject = JSON.parseObject(videoInfoJson); + switch (jsonObject.getInteger("code")) { + case 0 -> { + JSONObject data = jsonObject.getJSONObject("data"); + // 标题 + String title = data.getString("title"); + // 封面url + String picUrl = data.getString("pic"); + // up主 + String ownerName = data.getJSONObject("owner").getString("name"); + // 分区 + String tname = data.getString("tname"); + // 播放量 + Integer view = data.getJSONObject("stat").getInteger("view"); + // 收藏 + Integer favorite = data.getJSONObject("stat").getInteger("favorite"); + // 投币 + Integer coin = data.getJSONObject("stat").getInteger("coin"); + // 点赞 + Integer like = data.getJSONObject("stat").getInteger("like"); + // 投稿 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String pubdate = LocalDateTime.ofInstant( + Instant.ofEpochSecond(data.getLong("pubdate")), + ZoneId.systemDefault() + ).format(formatter); + // 简介 + String desc = data.getString("desc"); + // ID + String aid = data.getString("aid"); + + return ArrayMsgUtils.builder() + .text(title + "\n") + .img("base64://" + FileUtils.fileToBase64(URI.create(picUrl))) + .text("up主:" + ownerName + "\n") + .text("分区:" + tname + "\n") + .text("播放:" + view + " ") + .text("收藏:" + favorite + "\n") + .text("投币:" + coin + " ") + .text("点赞:" + like + "\n") + .text("投稿:" + pubdate + "\n") + .text("简介:" + desc.substring(0, min(desc.length(), 57)) + "\n") + .text("ID:" + aid + "\n") + .build(); + } + case -400 -> { + return ArrayMsgUtils.builder().text("请求错误").build(); + } + case -403 -> { + return ArrayMsgUtils.builder().text("权限不足").build(); + } + case -404 -> { + return ArrayMsgUtils.builder().text("无视频").build(); + } + case 62002 -> { + return ArrayMsgUtils.builder().text("稿件不可见").build(); + } + case 62004 -> { + return ArrayMsgUtils.builder().text("稿件审核中").build(); + } + default -> { + return ArrayMsgUtils.builder().text("解析失败,未知错误").build(); + } + } + } + + /** + * 视频基本信息 + * 参考文档 https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md + * + * @param id 传入BV号或av号字符串 + * @return json字符串 + */ + private String getVideoInfoJson(String id) { + if (id == null || id.isBlank()) { + throw new IllegalArgumentException(); + } + + // 判断id类型 + // BV bv 可大写可小写 + // av 只能小写 + String param; + if (id.startsWith("av")) { + param = "?aid=" + Integer.parseInt(id.substring(2)); + } else if (id.startsWith("BV") || id.startsWith("bv")) { + param = "?bvid=" + id; + } else { + throw new IllegalArgumentException(); + } + + // 访问api得到数据 + try (HttpClient httpClient = HttpClient.newHttpClient()) { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://api.bilibili.com/x/web-interface/wbi/view" + param)) + .header("Content-Type", "application/json") + .GET() + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + return response.body(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/shitlime/era/utils/FileUtils.java b/src/main/java/com/shitlime/era/utils/FileUtils.java index 897fc65..9142108 100644 --- a/src/main/java/com/shitlime/era/utils/FileUtils.java +++ b/src/main/java/com/shitlime/era/utils/FileUtils.java @@ -1,13 +1,21 @@ package com.shitlime.era.utils; +import lombok.extern.slf4j.Slf4j; + import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.Base64; +@Slf4j public class FileUtils { /** * 计算文件的 base64 值 + * * @param path * @return */ @@ -16,10 +24,36 @@ public static String fileToBase64(String path) { BufferedInputStream stream = new BufferedInputStream(new FileInputStream(path)); byte[] bytes = stream.readAllBytes(); stream.close(); - Base64.Encoder encoder = Base64.getEncoder(); - return encoder.encodeToString(bytes); + return Base64.getEncoder().encodeToString(bytes); } catch (IOException e) { throw new RuntimeException(e); } } + + /** + * 获取并计算网络文件的 base64 值 + * + * @param uri 网络地址(URL) + * @return + */ + public static String fileToBase64(URI uri) { + // 访问uri得到文件的数据 + // 转换成base64字符串返回 + try (HttpClient httpClient = HttpClient.newHttpClient()) { + HttpRequest request = HttpRequest.newBuilder() + .uri(uri) + .build(); + // 发送请求并获取响应 + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray()); + + // 获取响应的字节数组 + byte[] responseBody = response.body(); + + // 将字节数组编码为 Base64 字符串 + return Base64.getEncoder().encodeToString(responseBody); + } catch (IOException | InterruptedException e) { + log.warn(e.getMessage()); + return null; + } + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3fa47ba..36ef8ce 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -19,6 +19,7 @@ shiro: - com.shitlime.era.plugins.RssManagePlugin - com.shitlime.era.plugins.TextToImagePlugin - com.shitlime.era.plugins.AIChatPlugin + - com.shitlime.era.plugins.BilibiliPlugin # 限速器(令牌桶算法) limiter: # 是否启用限速器 From f1de74c7b9ea7bb4ec94d16a6b4e5e624830124d Mon Sep 17 00:00:00 2001 From: shitlime Date: Fri, 6 Sep 2024 01:00:49 +0800 Subject: [PATCH 3/6] fix: fix send bvid condition --- src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java b/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java index 292a9ce..220abe1 100644 --- a/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java +++ b/src/main/java/com/shitlime/era/plugins/BilibiliPlugin.java @@ -37,7 +37,7 @@ public int onAnyMessage(Bot bot, AnyMessageEvent event) { List msgList = bilibiliService.autoGetVideoInfo(bvid); bot.sendMsg(event, msgList, true); // 如果消息不只有BV号,发送纯BV号 - if (msgPlain.trim().equals(bvid)) { + if (!msgPlain.trim().equals(bvid)) { bot.sendMsg(event, ArrayMsgUtils.builder().text(bvid).build(), true); } return MESSAGE_BLOCK; From 063a1af2feebe937c261ef4a99807185845c6c96 Mon Sep 17 00:00:00 2001 From: shitlime Date: Fri, 6 Sep 2024 01:13:29 +0800 Subject: [PATCH 4/6] chore: modify message --- src/main/java/com/shitlime/era/service/BilibiliService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/shitlime/era/service/BilibiliService.java b/src/main/java/com/shitlime/era/service/BilibiliService.java index efa96bf..f74b834 100644 --- a/src/main/java/com/shitlime/era/service/BilibiliService.java +++ b/src/main/java/com/shitlime/era/service/BilibiliService.java @@ -73,7 +73,7 @@ public List autoGetVideoInfo(String videoId) { .text("点赞:" + like + "\n") .text("投稿:" + pubdate + "\n") .text("简介:" + desc.substring(0, min(desc.length(), 57)) + "\n") - .text("ID:" + aid + "\n") + .text("ID:av" + aid) .build(); } case -400 -> { From e7c6bd54f95b6bbc8eeb5bf9fd96112471183799 Mon Sep 17 00:00:00 2001 From: shitlime Date: Thu, 26 Sep 2024 00:05:13 +0800 Subject: [PATCH 5/6] chore: update unicode blocks information --- src/main/resources/unicode/Blocks.txt | 19 +++++++++++++++---- src/main/resources/unicode/Blocks_cn.txt | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/resources/unicode/Blocks.txt b/src/main/resources/unicode/Blocks.txt index 8fa3eaa..1517dde 100644 --- a/src/main/resources/unicode/Blocks.txt +++ b/src/main/resources/unicode/Blocks.txt @@ -1,7 +1,8 @@ -# Blocks-15.1.0.txt -# Date: 2023-07-28, 15:47:20 GMT -# © 2023 Unicode®, Inc. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# Blocks-16.0.0.txt +# Date: 2024-02-02 +# © 2024 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -217,6 +218,7 @@ FFF0..FFFF; Specials 10500..1052F; Elbasan 10530..1056F; Caucasian Albanian 10570..105BF; Vithkuqi +105C0..105FF; Todhri 10600..1077F; Linear A 10780..107BF; Latin Extended-F 10800..1083F; Cypriot Syllabary @@ -239,6 +241,7 @@ FFF0..FFFF; Specials 10C00..10C4F; Old Turkic 10C80..10CFF; Old Hungarian 10D00..10D3F; Hanifi Rohingya +10D40..10D8F; Garay 10E60..10E7F; Rumi Numeral Symbols 10E80..10EBF; Yezidi 10EC0..10EFF; Arabic Extended-C @@ -258,12 +261,14 @@ FFF0..FFFF; Specials 11280..112AF; Multani 112B0..112FF; Khudawadi 11300..1137F; Grantha +11380..113FF; Tulu-Tigalari 11400..1147F; Newa 11480..114DF; Tirhuta 11580..115FF; Siddham 11600..1165F; Modi 11660..1167F; Mongolian Supplement 11680..116CF; Takri +116D0..116FF; Myanmar Extended-C 11700..1174F; Ahom 11800..1184F; Dogra 118A0..118FF; Warang Citi @@ -274,6 +279,7 @@ FFF0..FFFF; Specials 11AB0..11ABF; Unified Canadian Aboriginal Syllabics Extended-A 11AC0..11AFF; Pau Cin Hau 11B00..11B5F; Devanagari Extended-A +11BC0..11BFF; Sunuwar 11C00..11C6F; Bhaiksuki 11C70..11CBF; Marchen 11D00..11D5F; Masaram Gondi @@ -288,12 +294,15 @@ FFF0..FFFF; Specials 12F90..12FFF; Cypro-Minoan 13000..1342F; Egyptian Hieroglyphs 13430..1345F; Egyptian Hieroglyph Format Controls +13460..143FF; Egyptian Hieroglyphs Extended-A 14400..1467F; Anatolian Hieroglyphs +16100..1613F; Gurung Khema 16800..16A3F; Bamum Supplement 16A40..16A6F; Mro 16A70..16ACF; Tangsa 16AD0..16AFF; Bassa Vah 16B00..16B8F; Pahawh Hmong +16D40..16D7F; Kirat Rai 16E40..16E9F; Medefaidrin 16F00..16F9F; Miao 16FE0..16FFF; Ideographic Symbols and Punctuation @@ -308,6 +317,7 @@ FFF0..FFFF; Specials 1B170..1B2FF; Nushu 1BC00..1BC9F; Duployan 1BCA0..1BCAF; Shorthand Format Controls +1CC00..1CEBF; Symbols for Legacy Computing Supplement 1CF00..1CFCF; Znamenny Musical Notation 1D000..1D0FF; Byzantine Musical Symbols 1D100..1D1FF; Musical Symbols @@ -325,6 +335,7 @@ FFF0..FFFF; Specials 1E290..1E2BF; Toto 1E2C0..1E2FF; Wancho 1E4D0..1E4FF; Nag Mundari +1E5D0..1E5FF; Ol Onal 1E7E0..1E7FF; Ethiopic Extended-B 1E800..1E8DF; Mende Kikakui 1E900..1E95F; Adlam diff --git a/src/main/resources/unicode/Blocks_cn.txt b/src/main/resources/unicode/Blocks_cn.txt index a2c969a..14d01af 100644 --- a/src/main/resources/unicode/Blocks_cn.txt +++ b/src/main/resources/unicode/Blocks_cn.txt @@ -1,7 +1,8 @@ -# Blocks-15.1.0.txt -# Date: 2023-07-28, 15:47:20 GMT -# © 2023 Unicode®, Inc. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# Blocks-16.0.0.txt +# Date: 2024-02-02 +# © 2024 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -217,6 +218,7 @@ FFF0..FFFF; Specials | 特殊字符 10500..1052F; Elbasan | 埃尔巴桑文 10530..1056F; Caucasian Albanian | 高加索阿尔巴尼亚文 10570..105BF; Vithkuqi +105C0..105FF; Todhri 10600..1077F; Linear A | 线形文字A 10780..107BF; Latin Extended-F | 拉丁文扩展-F 10800..1083F; Cypriot Syllabary | 塞浦路斯音节文字 @@ -239,6 +241,7 @@ FFF0..FFFF; Specials | 特殊字符 10C00..10C4F; Old Turkic | 古突厥文 10C80..10CFF; Old Hungarian | 古匈牙利文 10D00..10D3F; Hanifi Rohingya | 哈尼斐罗兴亚文 +10D40..10D8F; Garay 10E60..10E7F; Rumi Numeral Symbols | 鲁米数字符号 10E80..10EBF; Yezidi | 耶兹迪文 10EC0..10EFF; Arabic Extended-C | 阿拉伯语扩展 C @@ -258,12 +261,14 @@ FFF0..FFFF; Specials | 特殊字符 11280..112AF; Multani | 穆尔坦文 112B0..112FF; Khudawadi | 胡达瓦迪文 11300..1137F; Grantha | 格兰塔文 +11380..113FF; Tulu-Tigalari 11400..1147F; Newa | 新阿文 11480..114DF; Tirhuta | 提尔胡塔文 11580..115FF; Siddham | 悉昙文 11600..1165F; Modi | 莫迪文 11660..1167F; Mongolian Supplement | 蒙古文补充 11680..116CF; Takri | 塔克里文 +116D0..116FF; Myanmar Extended-C | 缅甸扩展-C 11700..1174F; Ahom | 阿洪姆文 11800..1184F; Dogra | 多格拉文 118A0..118FF; Warang Citi | 瓦朗奇提文 @@ -274,6 +279,7 @@ FFF0..FFFF; Specials | 特殊字符 11AB0..11ABF; Unified Canadian Aboriginal Syllabics Extended-A | 加拿大原住民统一音节文字扩展-A 11AC0..11AFF; Pau Cin Hau | 泼金豪文 11B00..11B5F; Devanagari Extended-A | 梵文字母扩展-A +11BC0..11BFF; Sunuwar 11C00..11C6F; Bhaiksuki | 布海书吉文 11C70..11CBF; Marchen | 马尔琴文 11D00..11D5F; Masaram Gondi | 马萨兰冈迪文 @@ -288,12 +294,15 @@ FFF0..FFFF; Specials | 特殊字符 12F90..12FFF; Cypro-Minoan | 塞浦路斯-米诺斯文 13000..1342F; Egyptian Hieroglyphs | 埃及象形文字 13430..1345F; Egyptian Hieroglyph Format Controls | 埃及象形文字格式控制 +13460..143FF; Egyptian Hieroglyphs Extended-A | 埃及象形文字扩展-A 14400..1467F; Anatolian Hieroglyphs | 安纳托利亚象形文字 +16100..1613F; Gurung Khema 16800..16A3F; Bamum Supplement | 巴姆穆文补充 16A40..16A6F; Mro | 勐罗文 16A70..16ACF; Tangsa | 唐萨 16AD0..16AFF; Bassa Vah | 巴萨瓦文 16B00..16B8F; Pahawh Hmong | 帕豪苗文 +16D40..16D7F; Kirat Rai 16E40..16E9F; Medefaidrin | 梅德费德林文 16F00..16F9F; Miao | 苗文 16FE0..16FFF; Ideographic Symbols and Punctuation | 表意符号和标点 @@ -308,6 +317,7 @@ FFF0..FFFF; Specials | 特殊字符 1B170..1B2FF; Nushu | 女书 1BC00..1BC9F; Duployan | 杜普洛延速记 1BCA0..1BCAF; Shorthand Format Controls | 速记格式控制 +1CC00..1CEBF; Symbols for Legacy Computing Supplement | 旧式计算符号补充 1CF00..1CFCF; Znamenny Musical Notation | Znamenny 音乐记谱法 1D000..1D0FF; Byzantine Musical Symbols | 拜占庭音乐符号 1D100..1D1FF; Musical Symbols | 音乐符号 @@ -325,6 +335,7 @@ FFF0..FFFF; Specials | 特殊字符 1E290..1E2BF; Toto | 托托文 1E2C0..1E2FF; Wancho | 万乔文 1E4D0..1E4FF; Nag Mundari +1E5D0..1E5FF; Ol Onal 1E7E0..1E7FF; Ethiopic Extended-B | 埃塞俄比亚文扩展-B 1E800..1E8DF; Mende Kikakui | 门德基卡库文 1E900..1E95F; Adlam | 阿德拉姆文 From 396658760a2fff7b324c072eb2f9a6c42a055921 Mon Sep 17 00:00:00 2001 From: shitlime Date: Sun, 2 Feb 2025 19:22:02 +0800 Subject: [PATCH 6/6] feat: get bilibili video skip segments --- .../shitlime/era/service/BilibiliService.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/main/java/com/shitlime/era/service/BilibiliService.java b/src/main/java/com/shitlime/era/service/BilibiliService.java index f74b834..48a59ec 100644 --- a/src/main/java/com/shitlime/era/service/BilibiliService.java +++ b/src/main/java/com/shitlime/era/service/BilibiliService.java @@ -1,6 +1,7 @@ package com.shitlime.era.service; import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.mikuac.shiro.common.utils.ArrayMsgUtils; import com.mikuac.shiro.model.ArrayMsg; @@ -18,6 +19,7 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.StringJoiner; import static java.lang.Math.min; @@ -61,6 +63,41 @@ public List autoGetVideoInfo(String videoId) { String desc = data.getString("desc"); // ID String aid = data.getString("aid"); + String bvid = data.getString("bvid"); + + // 查询跳过片段信息 + String segmentsJson = getVideoSkipSegmentsJson(bvid); + if (segmentsJson != null) { + JSONArray segments = JSON.parseArray(segmentsJson); + long segmentsCount = segments.size(); + StringJoiner segmentsInfo = new StringJoiner("\n"); + for (Object obj : segments) { + JSONObject jo = (JSONObject) obj; + JSONArray seg = jo.getJSONArray("segment"); + if (seg != null && seg.size() == 2) { + double start = seg.getDouble(0); // 开始时间 + double end = seg.getDouble(1); // 结束时间 + segmentsInfo.add(formatTime(start) + " - " + formatTime(end)); + } + } + if (segmentsCount > 0) { + return ArrayMsgUtils.builder() + .text("【⚠该视频可能含有广告⚠】\n" + title + "\n") + .img("base64://" + FileUtils.fileToBase64(URI.create(picUrl))) + .text("up主:" + ownerName + "\n") + .text("分区:" + tname + "\n") + .text("播放:" + view + " ") + .text("收藏:" + favorite + "\n") + .text("投币:" + coin + " ") + .text("点赞:" + like + "\n") + .text("投稿:" + pubdate + "\n") + .text("简介:" + desc.substring(0, min(desc.length(), 57)) + "\n") + .text("ID:av" + aid) + .text("⚠疑似广告片段(" + segmentsCount + "):\n") + .text(segmentsInfo.toString()) + .build(); + } + } return ArrayMsgUtils.builder() .text(title + "\n") @@ -91,6 +128,9 @@ public List autoGetVideoInfo(String videoId) { case 62004 -> { return ArrayMsgUtils.builder().text("稿件审核中").build(); } + case 62012 -> { + return ArrayMsgUtils.builder().text("仅UP主自己可见").build(); + } default -> { return ArrayMsgUtils.builder().text("解析失败,未知错误").build(); } @@ -134,4 +174,45 @@ private String getVideoInfoJson(String id) { throw new RuntimeException(e); } } + + /** + * 获取跳过片段信息 + * 参考文档 https://github.com/hanydd/BilibiliSponsorBlock/wiki/API + * + * @param id 传入视频的BV号字符串 + * @return json字符串 + */ + private String getVideoSkipSegmentsJson(String id) { + // 访问api得到数据 + try (HttpClient httpClient = HttpClient.newHttpClient()) { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://bsbsb.top/api/skipSegments?videoID=" + id)) + .header("Content-Type", "application/json") + .GET() + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() == 200) { + return response.body(); + } + return null; + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + /** + * 将秒数转换为时:分:秒格式 + * + * @param seconds 秒数 + * @return 时:分:秒格式的字符串 + */ + private static String formatTime(double seconds) { + int totalSeconds = (int) seconds; // 取整 + int hours = totalSeconds / 3600; // 计算小时 + int minutes = (totalSeconds % 3600) / 60; // 计算分钟 + int secs = totalSeconds % 60; // 计算秒数 + + // 格式化输出 + return String.format("%02d:%02d:%02d", hours, minutes, secs); + } }