304 Commits

Author SHA1 Message Date
7c49702d87 feat(AnimeController): 新增 AnimeController 并更新版本号
- 添加 AnimeController 类,实现获取今日和明日番剧功能
- 更新项目版本号至 QQBot v.1.7.24
2025-05-17 07:16:18 +08:00
95a5bf5467 refactor: 优化代码并更新版本号
- 注释掉 GPT 消息列表相关代码,返回空列表替代
- 优化 AppTools 中异常处理,使用日志记录替代 printStackTrace
- 更新 BiliVideo 中视频下载链接和参数
- 替换 OpenPC 中的 Redis 操作为执行唤醒命令
- 更新 QQBotApplication版本号至 v.1.7.23
-简化 QQBotManager 中的版本信息输出
2025-05-16 09:24:29 +08:00
dbec50b023 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	src/main/java/com/yutou/qqbot/QQBotApplication.java
#	src/main/java/com/yutou/qqbot/utlis/ZVVImageUtils.java
2025-02-28 18:07:42 +08:00
bc378a5c59 feat(gpt): 优化临时消息处理逻辑
- 修改 clear 方法,移除同步关键字
- 优化 sendTmpMessage 方法,增加日志记录和处理流程
- 更新 GetSeTu 类,改进擦边图片请求的回复文案
-调整 HttpLoggingInterceptor,启用日志输出
- 更新 QQBotApplication 版本号至 1.7.21
2025-02-28 18:07:09 +08:00
e53760f280 feat(bot): 添加张vv表情包生成功能
- 新增 ZVVImageUtils 类实现表情包生成逻辑
- 在 BaiduGPT 类中集成该功能,支持回复如何评论/评价相关问题
- 更新 QQBotApplication 版本号至 1.7.20
- 优化 QQBean 类中的随机数逻辑
- 移除 MessageChainBuilder 类中冗余的 toString 方法
- 删除 QQSetu 类中未使用的 MessageChainBuilder 导包
2025-02-22 13:29:43 +08:00
f770fcc8fb feat(BaiduGPT): 更新雌小鬼角色设定和禁言惩罚机制
- 重新定义角色人格核心,增加甜腻声线和波浪号等特征
- 设计全新的惩戒执行官设定,包括时间计算和大小姐形态切换- 更新模板示例,增加具体的参数注入
- 优化代码格式,提高可读性
-版本号升级到 QQBot v.1.7.19
2025-02-20 10:19:18 +08:00
204907d738 feat(gpt): 新增临时消息发送功能并优化相关命令
- 在 AbsGPTManager 中添加 sendTmpMessage 方法,用于发送临时消息
- 更新 BaiduGPTManager 实现 sendTmpMessage 方法
- 修改 GetSeTu 和 QQBean模型,集成临时消息发送功能
- 更新 BaiduGPT 示例代码,演示临时消息发送用法
- 将 QQBot 版本号更新到 v1.7.17
2025-02-19 18:26:19 +08:00
925a7af045 feat(gpt): 新增临时消息发送功能并优化相关命令
- 在 AbsGPTManager 中添加 sendTmpMessage 方法,用于发送临时消息
- 更新 BaiduGPTManager 实现 sendTmpMessage 方法
- 修改 GetSeTu 和 QQBean模型,集成临时消息发送功能
- 更新 BaiduGPT 示例代码,演示临时消息发送用法
- 将 QQBot 版本号更新到 v1.7.17
2025-02-19 17:10:42 +08:00
a7676fa6db feat(gpt): 更新百度大模型并添加模型列表展示
- 添加了百度大模型列表的展示功能
- 百度大模型新增v2模式,支持ds模型
- 优化了代码格式和结构
- 版本号更新到 QQBot v.1.7.15
2025-02-19 11:09:18 +08:00
9ab99b22e2 feat(bot): 增加定时清理功能并优化消息发送逻辑- 在 AbsGPTManager 中添加定时任务调度功能,用于定期清理资源
- 修改 BaiduGPT 类中的消息发送逻辑,增加定时清理调度
- 更新 BaiduGPTManager 中的 sendMessage 方法,添加用户锁注释
- 升级 qianfan 依赖至0.1.4 版本
- 更新 QQBot 版本号至 1.7.14
2025-02-19 10:24:13 +08:00
5d7ec8e67d refactor(bilibili):暂时屏蔽 B 站直播签到功能
- 将直播签到请求替换为固定返回消息 "已停用"
2025-02-17 10:15:33 +08:00
8ea93c0d61 feat(gpt): 更新模型切换逻辑并移除冗余代码
- 在 BaiduGPT.java 中添加配置保存逻辑,切换模型时更新配置
- 在 BaiduGPTManager 和 SiliconGPTManager 中实现 setModel 方法,统一模型设置逻辑
- 移除 BaiduGPTManager 中的 setModelFor40 和 setModelFor35 方法,简化代码结构
- 更新 QQBotApplication 版本号至1.7.13
2025-02-13 17:51:40 +08:00
9e062976ac feat(gpt): 支持切换 GPT 模型
- 新增配置项 GPT 用于选择 GPT 模型类型
- 实现 BaiduGPT 和 SiliconGPT 两种模型的切换逻辑
- 优化 SiliconGPTManager 初始化,支持自定义模型配置
- 更新 QQBot 版本号至 1.7.12
2025-02-13 17:38:28 +08:00
7637aa2fec Merge remote-tracking branch 'origin/dev' into dev 2025-02-12 18:25:37 +08:00
9347eb9cde fix(BaiduGPT): 修复模型切换显示错误
- 将显示切换的模型名称改为当前 GPT 管理器的简单名称
- 移除了不必要的设置模型名称方法调用
2025-02-12 18:23:10 +08:00
bc483e50b5 refactor(GroupApi): 重构群组禁言接口
- 将 POST 请求改为 GET 请求
-移除 @FormUrlEncoded 注解
- 使用 @Query 注解替换 @Field 注解
2025-02-10 20:18:45 +08:00
b55991798f fix(BaiduGPT): 修复 GPT 切换命令的文本处理
- 修正了从消息中提取目标 GPT 模型名称的逻辑
- 提高了命令的准确性和鲁棒性
2025-02-10 18:17:13 +08:00
12f224b8f3 fix(BaiduGPT): 修复模型设置后未返回问题
- 在设置 Baidu GPT 模型后添加 return 语句,避免继续执行其他逻辑
- 更新应用版本号至 QQBot v.1.7.11.5
2025-02-10 18:06:53 +08:00
068964145f feat(gpt): 支持硅基大模型并优化 GPT功能
- 新增对硅基大模型的支持,可通过指令切换使用
- 优化 GPT 模型切换逻辑,支持更多自定义选项
- 优化日志级别和网络请求超时设置
2025-02-10 13:44:31 +08:00
864d5960a7 commit feat: 新增和改进HTTP请求处理及文件下载功能
- 新增文件下载功能:
  - 新增 `FileBody.java` 类,定义文件下载的数据结构。
  - 新增 `FileCallback.java` 类,处理文件下载的回调逻辑,包括线程池管理和下载进度报告。
  - 新增 `HttpDownloadUtils.java` 工具类,提供异步和同步的文件下载方法,并支持下载接口回调。

- 改进HTTP请求处理:
  - 修改 `NapCatQQ.java` 的 `onResponse` 方法,增加对响应头(`Headers`)的处理。
  - 修改 `GetRequestParams.java` 和 `PostRequestParams.java` 的 `getRequest` 方法,支持在请求中添加自定义Header。
  - 修改 `HttpCallback.java` 的 `onResponse` 方法,增加对响应头(`Headers`)的处理。

- 优化HTTP日志记录:
  - 修改 `HttpLoggingInterceptor.java`,调整日志级别为默认输出响应体,修复日志输出格式和异常处理问题。

- 改进BaseApi类:
  - 修改 `BaseApi.java`,增加对请求头的支持,并优化错误处理逻辑。
  - 在拦截器中处理非成功的响应码,返回统一格式的错误信息,避免业务逻辑中重复处理。

- 更新QQBotManager API回调:
  - 修改 `QQBotManager.java`,更新API回调方法以处理响应头(`Headers`),确保所有回调方法一致。

- 新增GPT API交互功能:
  - 新增 `OpenAiBean.java` 类,定义与OpenAI交互的数据结构,包含响应中的各个字段。
  - 新增 `SiliconGPTManager.java` 类,实现新的GPT管理器,处理与Silicon GPT API的交互。
  - 新增 `GPTApi.java` 类,提供与GPT API交互的基础配置和API调用方法。
  - 新增 `GPTBuilder.java` 类,用于构建发送给GPT API的请求对象。

- 改进GPT管理器:
  - 修改 `AbsGPTManager.java`,添加锁机制,防止同一用户同时发起多个请求。
  - 提供获取消息列表的方法,限制历史消息的最大数量。
  - 支持设置模型版本。
  - 修改 `BaiduGPTManager.java`,移除重复的清除方法,继承自父类。
  - 使用父类提供的方法获取消息列表,简化代码逻辑。

- 优化和重构:
  - 进一步优化 `HttpLoggingInterceptor.java` 的日志记录逻辑,提高性能和可读性。
  - 重构 `BaseApi.java` 初始化方法,简化代码逻辑,提高可读性。

这些改动增强了HTTP请求处理能力,增加了文件下载功能,并为与GPT API的交互提供了支持。
2025-02-08 18:27:00 +08:00
94890f001c feat(gpt): 更新模型并优化版本显示
- 将 ERNIE-3.5-8K 模型替换为 ERNIE-Speed-128K 模型
- 修改 getGPTVersion 方法以直接返回当前模型名称
- 更新 QQBot 版本号至 1.7.10
2025-02-05 18:18:48 +08:00
73566a41e5 build:升级 qianfan 依赖版本
- 将 qianfan 依赖版本从 0.1.1 升级到 0.1.3
2025-02-05 10:40:02 +08:00
56774792c1 feat(gpt): 重构 GPT 管理器并添加新功能
- 重构 AbsGPTManager 抽象类,添加多个新方法
- 新增 sendMessage、textToImage、imageToText、getGPTVersion 等方法
- 添加 setMaxMessageCount 方法,用于设置最大消息数量
- 实现 getManager 方法,根据类获取相应的 GPT 管理器实例
- 更新 BaiduGPTManager 类,实现新增的方法
2025-02-05 10:33:12 +08:00
e7fae929a1 refactor(gpt): 重构 GPT 相关代码并优化功能
- 新增 AbsGPTManager 抽象类,定义 GPT 管理器的通用接口
- 重命名 BaiduGPTManager 类,使其位于 com.yutou.qqbot.gpt 包中
- 更新相关引用和依赖
- 优化部分代码结构,提高可维护性
2025-02-04 18:15:15 +08:00
09305ae824 feat(BaiduGPTManager):优化图片描述功能并添加翻译功能
- 更新图片转文本的提示语,要求更详细的描述
- 添加将英文结果翻译成中文的功能
- 优化翻译提示语,确保准确翻译
- 更新版本号至 QQBot v.1.7.9.1
-调整日志设置的加载顺序
2025-02-04 18:00:07 +08:00
1041dfa909 feat(bot): 增加图片处理功能并优化日志系统
- 新增 textToImage 和 imageToText 功能,实现文本与图片的相互转换
- 优化日志系统,使用 log4j2 实现动态日志记录- 重构 BaiduGPTManager 类,增加多线程支持和错误处理
- 更新 MessageHandleBuild 类,支持 message_id 参数
- 修复部分功能的逻辑错误,提高系统稳定性
2025-02-04 17:13:48 +08:00
237c9273ca feat(QQBot): 更新版本并优化消息发送功能
- 将版本号从 v.1.7.7 升级到 v.1.7.8
-重构 sendMessage 方法,支持发送包含图片和回复的消息
- 更新服务器版本查询 URL 为 HTTPS
- 注释掉版本查询时的服务器消息发送
2025-02-03 14:45:00 +08:00
607c05e028 更新B站相关签到时间 2024-10-09 10:18:21 +08:00
df0337b006 更新为1.7.7 2024-09-20 09:31:59 +08:00
ebe96127e5 调整QQ对外接口 2024-06-09 11:37:39 +08:00
120392be17 更新小米路由器API调用接口
更新小米路由器获取公网IP的接口
2024-06-03 22:01:05 +08:00
6ed42d3e80 update 2024-05-21 16:26:21 +08:00
9903056551 修复百度没有上下文问题 2024-05-21 16:24:25 +08:00
10c4459936 移除多余输出 2024-05-10 13:25:46 +08:00
632b11d242 Merge pull request '改成onebot-11通用接口' (#9) from dev_HTTP服务化 into master
Reviewed-on: #9
OJBK
2024-05-10 13:09:42 +08:00
b4230a4809 调整动画key 2024-05-10 13:06:30 +08:00
604d186cc2 修复百度版本保存失败问题 2024-05-10 13:03:23 +08:00
2c37c19cc9 替换百度key 2024-05-06 10:51:47 +08:00
808ec3bd0a 更新 src/main/java/com/yutou/qqbot/utlis/BaiduGPTManager.java 2024-05-05 20:24:28 +08:00
400f2df6ab 优化百度文心一言保存版本到文件 2024-05-05 17:13:10 +08:00
7e9fa60f6a 新增图片支持File
调整涩图模块为先自己下载,无法下载再丢url给qq机器人
移除部分日志
2024-05-05 16:50:37 +08:00
d4b0a78fa9 修改日志 2024-05-04 18:25:15 +08:00
4ccaa4b78e 修改日志 2024-05-04 18:23:47 +08:00
c74033fed7 修改日志 2024-05-04 18:21:46 +08:00
5a7382d02c 完成基本功能转移 2024-05-04 17:26:27 +08:00
3b52742ac1 Merge pull request 'dev_该合并了' (#8) from dev_ into master
Reviewed-on: #8
2024-01-17 17:23:44 +08:00
e40c19016a Merge branch 'master' into dev_ 2024-01-17 17:23:32 +08:00
4dce74eaf8 提取B站API统一管理 2024-01-17 17:22:21 +08:00
68fd6efdf4 修复空字符串判断错误代码 2024-01-17 15:49:45 +08:00
2000efdd55 补充QQ发出AI内容消息 2024-01-17 15:19:25 +08:00
9ea1450066 新增B站AI总结功能 2024-01-17 15:12:40 +08:00
3437a5386f 修复B站无法登陆问题 2024-01-08 17:31:21 +08:00
177c91c370 update 2024-01-08 10:46:23 +08:00
5af58336ec update gpt 2023-10-26 14:19:18 +08:00
b177561df4 update gpt 2023-10-26 14:08:44 +08:00
126f25af81 update gpt 2023-09-20 22:21:09 +08:00
c48db62d00 update 2023-09-13 15:30:46 +08:00
e595cff31d update 2023-09-13 15:22:56 +08:00
9b70685949 update 2023-09-13 10:47:38 +08:00
a317767ae7 遥遥领先
遥遥领先
2023-09-05 01:33:23 +08:00
5846ef5016 遥遥领先 2023-09-05 01:06:00 +08:00
91a18835c3 遥遥领先 2023-09-05 00:54:07 +08:00
694239eac9 遥遥领先 2023-09-05 00:32:03 +08:00
af3f85618d 遥遥领先 2023-09-04 12:19:37 +08:00
6eedb9786e 更换百合会签到 2023-08-11 09:37:16 +08:00
d56d6edf19 更换摸鱼日历的api 2023-08-08 11:30:01 +08:00
084d8901e9 更换摸鱼日历的api 2023-08-02 09:42:53 +08:00
00816083b9 调整摸鱼图提前下载时间 2023-08-01 14:55:50 +08:00
8da7c2f572 新增QQ启动前检查签名服务器是否运行 2023-07-26 09:42:40 +08:00
e65eb62417 调整百度GPT的User为用户而不是群组 2023-07-25 17:17:42 +08:00
883f5bb820 update pom.xml 2023-07-25 16:56:48 +08:00
a34fafc39c 更新QQ机器人
修复机器人协议问题
2023-07-25 16:04:50 +08:00
9fdf670c26 新增百度文言一心GPT接口模块 2023-07-25 14:48:11 +08:00
00cdf7b96e 修复B站直播签到问题 2023-07-21 01:10:03 +08:00
2c456702d8 调整B站签到出错时输出日志 2023-07-20 13:32:30 +08:00
4aa0a53cc5 更新QQ机器人版本
新增扫码登录
2023-06-25 10:26:13 +08:00
3d3046f1d7 修复B站漫画签到的空指针错误 2023-06-25 08:40:24 +08:00
8df36edd2d 调整摸鱼日历API 2023-06-20 17:48:22 +08:00
808798028f 调整摸鱼日历API 2023-06-20 17:48:04 +08:00
4f5bcc9df3 修复下载摸鱼图片会死循环问题
修复电池签到任务周任务为空问题
2023-06-20 09:40:27 +08:00
43a816066d fix version 2023-04-18 07:48:19 +08:00
9fc377f070 update 更新selenium版本 2023-03-18 13:41:47 +08:00
83e3b5adae remove:MiRouter 2023-03-17 17:43:12 +08:00
b14601ef2c add:FixQQVersion 2023-03-17 17:39:14 +08:00
48501b09ff 修复B站每日签到没有周任务时的异常 2023-03-02 09:57:16 +08:00
a27d6c5a35 新增代理 2023-02-27 20:48:09 +08:00
0819bc58aa 更新 'src/main/java/com/yutou/qqbot/models/Commands/PaoPaoSleepWaring.java' 2023-02-23 22:40:49 +08:00
2e4e072201 update 2023-02-23 17:27:44 +08:00
ff9ae9cc36 更新 'src/main/java/com/yutou/qqbot/models/Commands/PaoPaoSleepWaring.java' 2023-02-23 17:23:08 +08:00
eb4264628d update 2023-02-23 17:21:57 +08:00
211773a230 更新 'src/main/java/com/yutou/qqbot/models/setu/GetSeTu.java'
优化输出中文冒号.
2023-02-14 16:43:21 +08:00
ab941e97e3 更新 'src/main/java/com/yutou/qqbot/models/setu/GetSeTu.java'
优化输出中文冒号
2023-02-14 16:42:15 +08:00
943a2c9334 优化B站直播间每日签到提示文本 2023-01-07 10:22:57 +08:00
3bc4c164e0 修复B站签到未登录时的状态 2023-01-06 01:31:01 +08:00
938d3d532a 新增B站大会员积分签到
修复B站操作前没做登陆校验的问题
2023-01-06 01:23:34 +08:00
5d15f24847 新增B站大会员积分签到
修复B站操作前没做登陆校验的问题
2023-01-05 15:18:53 +08:00
fec901970a 新增B站直播间领电池功能
新增B站APP操作相关API
优化B站登陆根据QQ号分账号存储
修复Redis获取列表时为空报错问题
2023-01-05 14:36:42 +08:00
083218b1cb 新增毛毛提醒,修改泡泡提醒为一小时 2022-11-20 19:08:32 +08:00
ae72956f68 update PaoPaoSleepWaring 2022-11-11 22:55:03 +08:00
1456675446 update PaoPaoSleepWaring 2022-11-11 22:54:15 +08:00
c2fc5c965a add PaoPaoSleepWaring 2022-11-11 22:43:46 +08:00
cf098877c3 update 木鱼音频 2022-11-10 20:36:37 +08:00
c9eceaccf3 update 木鱼音频 2022-11-10 20:29:49 +08:00
ab1facc747 add PaoPaoSleepWaring 2022-11-10 14:18:12 +08:00
5ac0b45540 fix WoodenFish.java 2022-11-07 09:41:45 +08:00
c146eac9c5 add WoodenFish.java 2022-11-04 10:28:58 +08:00
85fbce9f4f add WoodenFish.java 2022-11-04 10:25:17 +08:00
0de499fb57 fix BaiHeHui.java 2022-10-28 09:41:48 +08:00
7623858866 test1 2022-10-22 13:46:55 +08:00
6d9277ced5 update pom.xml 2022-10-17 09:50:42 +08:00
bcafd751e6 fix bili live sign bugs 2022-10-15 11:31:12 +08:00
5d2d41f176 fix bili live sign time sleep 2022-10-15 11:16:31 +08:00
6de3f5d738 fix int.parseInt 2022-10-15 11:10:46 +08:00
28167c7f49 add user info 2022-10-14 21:31:57 +08:00
22add886d5 add user info 2022-10-14 21:30:25 +08:00
47e4039127 add user info 2022-10-14 21:27:24 +08:00
3d730206b9 fix B站添加直播间失败 2022-10-14 21:14:11 +08:00
07361fb616 fix B站添加直播间失败 2022-10-14 21:11:31 +08:00
00985e7fb8 fix bili live sign bugs 2022-10-14 14:12:09 +08:00
960c3e9c56 add bilibili live signIn
add bilibili live room sign
2022-10-14 13:52:59 +08:00
8207498f2c add bilibili live signIn
add bilibili live room sign
2022-10-14 13:49:43 +08:00
fe48b030d9 新增涩图线上观看 2022-10-13 23:51:52 +08:00
de1fe79b09 新增涩图线上观看 2022-10-13 23:50:37 +08:00
1908c905ac 下载器支持代理 2022-10-13 23:28:04 +08:00
f0d61ffbb6 替换BT下载器 2022-10-09 00:03:34 +08:00
f46c09c6ed 移除日历提醒 2022-09-04 11:59:17 +08:00
7885f2bbfb update 2022-09-04 11:04:03 +08:00
f296d4c819 更新layui版本 2022-09-01 21:27:07 +08:00
283deb3e4a tmp 2022-08-22 22:05:06 +08:00
0ffc076a71 Merge remote-tracking branch 'origin/master' into dev_ 2022-08-22 21:41:24 +08:00
6d2b1e9264 tmp 2022-08-22 21:39:56 +08:00
0ee1be5f04 tmp 2022-08-22 21:39:06 +08:00
204da16848 Merge pull request '新增B站视频下载功能' (#7) from dev_ into master
Reviewed-on: test/QQBot#7
Reviewed-by: root <583819556@163.com>
2022-08-15 02:39:56 +08:00
6857a1d5ea fix:#6 版本号未提交问题 2022-08-15 02:29:36 +08:00
e19d1cdeda add:新增B站视频下载接口及页面 2022-08-15 02:24:49 +08:00
39588831d4 Merge pull request '模块图文分离' (#5) from dev_ into master
Reviewed-on: test/QQBot#5
2022-08-05 11:58:22 +08:00
8160d64867 add:优化 #4 涩图模块图文分离 2022-08-05 11:52:45 +08:00
4fabd514a7 update:调整QQBot的返回值 2022-08-05 11:50:56 +08:00
03f8bc07ba Merge pull request 'update version' (#2) from dev_ into master
Reviewed-on: test/QQBot#2
2022-08-05 10:58:31 +08:00
61c9fc60a0 update version 2022-08-05 10:46:29 +08:00
8f8fa41acf update:涩图模块发送回执
fix:修复大头菜模块未关闭浏览器
del:移除未使用import
2022-08-05 10:45:16 +08:00
d737730768 update:优化脚本执行 2022-07-27 09:35:04 +08:00
5209843e86 update:优化脚本执行 2022-07-27 01:22:32 +08:00
21dd8033d1 update:重构脚本执行方式 2022-07-26 22:46:00 +08:00
af54377bb2 update:redis新增对map的支持 2022-07-26 22:45:11 +08:00
788bd24d92 update:redis新增对map的支持 2022-07-26 22:45:00 +08:00
08bbd247a4 fix:修复舰R脚本多调用了一次start 2022-07-25 13:31:24 +08:00
75b43e40e5 fix:修复舰R脚本多调用了一次start 2022-07-25 12:58:22 +08:00
ef8d46aa64 新增舰R脚本 2022-07-25 12:42:55 +08:00
886e3eae6f 新增舰R脚本 2022-07-25 12:39:03 +08:00
30fda14264 新增舰R脚本 2022-07-25 12:35:50 +08:00
c36044e6e4 add:Redis新增列表支持 2022-07-25 12:34:54 +08:00
8661d8f3e7 fix:调整了无头浏览器的流程:需要手动调用关闭浏览器方法
fix:调整了下载文件判断,如果下载结束后文件不存在则抛异常
2022-07-25 08:57:44 +08:00
c10abbe82e update 2022-07-23 10:49:28 +08:00
10675c373a update 2022-07-18 11:48:31 +08:00
67587d208b 更换扫描注解的方式 2022-07-16 15:59:20 +08:00
e085690446 更新QQ依赖 2022-07-16 13:04:09 +08:00
b475e008a2 更新QQ依赖 2022-07-16 12:42:04 +08:00
b2610a02b2 新增HiRes猪猪论坛签到 2022-07-16 12:35:15 +08:00
05e8814b91 改成使用注解来注册模块 2022-07-16 12:34:14 +08:00
d76090af75 更新摸鱼接口 2022-06-27 10:15:24 +08:00
299bc17758 更新依赖
百合会签到改为模拟登陆行为
WebClient导入Cookie修复时间异常问题
2022-06-27 10:02:47 +08:00
8ddfc339dd 更新依赖 2022-06-08 10:29:25 +08:00
7319944441 B站模块:修复字幕顶部过高问题 2022-05-28 17:03:47 +08:00
c1fd29232e B站模块:修复字幕过大的问题
B站模块:修复仅下载前6分钟字幕的问题
2022-05-09 11:55:12 +08:00
a7baf2a236 修复大头菜模块输出异常 2022-05-09 11:52:48 +08:00
af9be86762 调整WebClient代码 2022-05-05 09:31:30 +08:00
84c583ad38 新增B站视频下载功能
新增弹幕转ass功能
优化B站网络请求头代码
2022-05-04 22:30:56 +08:00
edfd663743 update 2022-05-03 16:53:09 +08:00
575df40591 修复大头菜报错问题(FastJSON) 2022-05-03 11:08:15 +08:00
50823587dd update 2022-05-03 10:20:44 +08:00
81929daebd update 2022-05-03 10:19:08 +08:00
bfe7ec77ab update 2022-05-03 10:11:04 +08:00
accead7817 移除调试代码 2022-05-03 09:46:40 +08:00
e0f81620a3 更新FastJSON
调整ChromeDriver参数
2022-05-03 09:40:34 +08:00
4031b07b0b 修复定时器获取bot为空导致异常问题 2022-04-28 09:56:56 +08:00
7943606dc0 修复FastJSON大版本更新后API变动 2022-04-28 09:50:33 +08:00
f1ed4be143 更新依赖
优化签到代码
2022-04-28 09:14:52 +08:00
f116568261 更新路径 2022-04-28 08:37:12 +08:00
694b5fb2ae chromedrive新增代理支持 2022-04-28 08:34:14 +08:00
ec6fce9a8d chromedrive新增代理支持 2022-04-28 08:23:12 +08:00
7ac9d1b188 涩图模块:修复随机色图不被统计的问题 2022-04-26 07:32:13 +08:00
2db6d1fd39 涩图模块:修复每日统计没效果 2022-04-22 00:40:30 +08:00
a90d493975 涩图模块:修复每日统计没效果 2022-04-22 00:37:56 +08:00
e96bdefb67 涩图模块:修复每日统计没效果 2022-04-22 00:35:48 +08:00
61feb23f16 涩图模块:修复每日统计没效果 2022-04-22 00:32:28 +08:00
3dac0288f3 涩图模块:修复每日统计没效果 2022-04-22 00:30:28 +08:00
fd5e32508f 涩图模块:修复每日统计没效果 2022-04-22 00:28:46 +08:00
7e1a0d6b92 涩图模块:修复每日统计没效果 2022-04-22 00:24:03 +08:00
05a892a135 涩图模块:修复每日统计没效果 2022-04-22 00:21:39 +08:00
46322572c7 涩图模块:修复每日统计没效果 2022-04-22 00:18:17 +08:00
938591531d 涩图模块:修复每日统计没效果 2022-04-22 00:16:36 +08:00
4d156ad861 涩图模块:修复每日统计没效果 2022-04-22 00:05:39 +08:00
7776fb3d01 涩图模块:新增每日统计 2022-04-21 00:01:30 +08:00
4f3fea8615 涩图模块:新增每日统计 2022-04-20 21:17:49 +08:00
15b0e14edd 涩图模块:支持多关键词搜索 2022-04-20 20:23:00 +08:00
dfd60919ad 涩图模块:空格替换成|以便支持多关键词搜索 2022-04-20 20:20:42 +08:00
5d4717d7a3 涩图模块:空格替换成|以便支持多关键词搜索 2022-04-20 20:18:49 +08:00
149e64d85f 涩图模块:空格替换成|以便支持多关键词搜索 2022-04-20 20:12:59 +08:00
731d7734d5 摸鱼模块:图片提前下载,后续再发送 2022-04-18 23:13:39 +08:00
b25a146e9a 涩图模块:搜不到图时随机来一张 2022-04-18 23:02:11 +08:00
1f7376c020 涩图模块:新增输出P站id 2022-04-18 22:57:15 +08:00
19a9fb0d1b 涩图模块:搜索不到后会尝试搜索非18、模糊搜索 2022-04-18 22:49:27 +08:00
086d773ac0 涩图模块:新增引用 2022-04-17 22:05:53 +08:00
f908066602 涩图模块:新增引用 2022-04-17 22:05:16 +08:00
d5da784033 涩图模块:匹配正则 2022-04-17 21:57:52 +08:00
5d05f279e8 涩图模块:匹配正则 2022-04-17 21:56:10 +08:00
6c9bd5dc81 涩图模块:匹配正则 2022-04-17 21:53:43 +08:00
c0b394c613 涩图模块:匹配正则 2022-04-17 21:43:09 +08:00
fdc1d7c880 涩图模块:匹配正则 2022-04-17 21:41:54 +08:00
1b593106ab 涩图模块:匹配正则 2022-04-17 21:37:08 +08:00
ccdca908cf 管理员模块:支持this关键词标识本群 2022-04-17 15:55:25 +08:00
9d88fef157 管理员模块:支持this关键词标识本群 2022-04-17 15:51:34 +08:00
a1831163cc 管理员模块:支持this关键词标识本群 2022-04-17 15:49:32 +08:00
4dfbee6d08 涩图模块:图源改成regular,减少图片大小
管理员模块:支持this关键词标识本群
2022-04-17 15:47:12 +08:00
10fd1d6863 涩图模块:区分色图和涩图关键词 2022-04-17 15:25:51 +08:00
4e56d31e43 新增提示 2022-04-17 02:24:26 +08:00
973a51428b 新增错误提示 2022-04-17 02:09:39 +08:00
490ae1b9dc 新增错误提示 2022-04-17 02:03:46 +08:00
e0e7195c57 新增错误提示 2022-04-17 01:54:55 +08:00
479ae1dfba 新增关键词 2022-04-17 01:49:48 +08:00
2558545ffe 新作关键词 2022-04-17 01:20:40 +08:00
f6c9748f48 下载支持代理 2022-04-17 01:06:31 +08:00
2da36d7918 换个二次元图源API试试 2022-04-17 00:58:34 +08:00
a83e92b947 换个二次元图源API试试 2022-04-17 00:14:30 +08:00
f2acbd9dfb update 2022-04-15 04:56:14 +08:00
7405c2a288 update 2022-04-15 04:46:26 +08:00
62ad0a65fd 调整摸鱼时间 2022-04-10 10:11:51 +08:00
409c12b76e 调整摸鱼时间 2022-04-10 09:22:48 +08:00
ac4466c374 调整摸鱼时间 2022-04-10 02:26:22 +08:00
c9a5732721 查询动画新增提示 2022-04-08 18:01:44 +08:00
00ebecb998 查询动画关键词获取到id后转id内容 2022-04-08 18:00:00 +08:00
6bc4ff40d5 查询动画仅限动画模块 2022-04-08 17:49:52 +08:00
6b19fa8f2f 查询动画仅限动画模块 2022-04-08 17:37:46 +08:00
3e709799d2 修复查动画无法保存图片的问题 2022-04-08 17:33:17 +08:00
7fa6c22ef8 修复查动画无法保存图片的问题 2022-04-08 17:11:56 +08:00
bcba637ad5 修复查动画无法保存图片的问题 2022-04-08 17:07:48 +08:00
d56e237b62 新增获取今日动画时提示 2022-04-08 17:03:27 +08:00
606e2e1ef1 允许动画模块在其他群使用 2022-04-08 17:00:07 +08:00
b695e0ff08 移除测试代码 2022-04-08 16:44:00 +08:00
4cbcba6b6e 新增摸鱼模块
测试大头菜
2022-04-08 16:42:08 +08:00
d35b1bdc42 新增模块名字
新番列表模块支持其他群了
定时器支持多个群了
2022-04-08 15:39:59 +08:00
5adb68b2ad 新增漫画购买功能 2022-04-08 13:50:40 +08:00
0ad33b328d 新增漫画购买功能 2022-04-08 13:48:21 +08:00
82c130a506 新增漫画购买功能 2022-04-08 13:46:54 +08:00
fe16be6693 新增漫画购买功能 2022-04-08 13:43:54 +08:00
fab0cdf497 新增漫画购买功能 2022-04-08 13:39:00 +08:00
3fdd2cf5ec 新增漫画购买功能 2022-04-08 13:36:55 +08:00
d9b3e7f558 新增漫画购买功能 2022-04-08 13:33:10 +08:00
9ddd8059dd 新增漫画购买功能 2022-04-08 13:31:54 +08:00
fa2761dbe2 新增漫画购买功能 2022-04-08 13:26:38 +08:00
d4b924f677 新增漫画购买功能 2022-04-08 13:23:49 +08:00
68cecf1e47 新增漫画购买功能 2022-04-08 13:08:12 +08:00
769f106fa3 新增漫画购买功能 2022-04-08 13:06:23 +08:00
2add54f3ad 新增漫画购买功能 2022-04-08 13:03:12 +08:00
159426ed09 新增漫画购买功能 2022-04-08 13:00:34 +08:00
4cc5567568 新增漫画购买功能 2022-04-08 12:59:47 +08:00
c04ada610f 修复B站登陆监测403问题 2022-04-08 02:40:33 +08:00
8145a1c313 update 2022-04-08 02:30:57 +08:00
61e35fb3c5 update 2022-04-08 02:28:41 +08:00
abfe65a534 新增B站漫画签到 2022-04-08 02:26:29 +08:00
d31534311f update 2022-04-07 14:01:49 +08:00
8e13a246ac update 2022-04-07 13:59:21 +08:00
a8b6b34406 update 2022-04-07 13:28:35 +08:00
bdb7d08622 更新pom.xml
新增更新qq和nas服务的指令
2022-04-07 13:08:58 +08:00
f825302b5f 新增临时磁链下载功能 2022-03-17 09:43:07 +08:00
28d98e573d 更新 'src/test/java/com/yutou/qqbot/QqBotApplicationTests.java' 2022-03-16 00:42:13 +08:00
e4ecde0db3 update 2022-03-11 21:07:06 +08:00
4503f2207f 修复忘记取消无头浏览器模式了 2022-02-09 09:22:03 +08:00
b4484f1424 新增NicePT签到
新增https工具
2022-02-08 12:27:07 +08:00
7cb003544b 修复接收文件大小限制 2022-01-28 21:34:56 +08:00
8d6fe31430 fix upload message isEmpty 2022-01-28 20:41:57 +08:00
e2083b1c47 新增文件接口 2022-01-28 20:27:45 +08:00
48651c384f 新增文件接口 2022-01-28 20:26:20 +08:00
bcae613e74 新增文件接口 2022-01-28 20:06:15 +08:00
5fa740c58f 修复QQ接口无法使用的问题 2022-01-16 12:31:39 +08:00
b5076323d7 优化获取小米路由器后台token 2022-01-09 18:55:02 +08:00
8e98929622 新增开门指令 2022-01-09 03:32:30 +08:00
aa935e8662 大头菜调整为本地站点从而提升加载速度
调整无头浏览器参数
升级fastjson版本
2022-01-08 13:23:52 +08:00
7d1128cc1d 大头菜支持群@ 2022-01-05 15:27:05 +08:00
ba7b933bdb 增加大头菜对群的支持
Model新增识别群并@发送人的方法
2022-01-02 10:47:48 +08:00
8f19448239 update 2022-01-02 01:00:24 +08:00
6e4fc0c3d3 修复QQ发图片会资源泄露的问题 2022-01-02 00:59:22 +08:00
6a68e95f45 新增涩图
更新QQ机器人
2022-01-02 00:40:09 +08:00
75f3a68faf 新增涩图 2022-01-02 00:18:48 +08:00
1bf0336b72 新增涩图 2022-01-02 00:16:36 +08:00
5b928afa82 新增涩图 2022-01-02 00:14:27 +08:00
eedd304c43 新增涩图 2022-01-01 23:40:14 +08:00
fb75b5206c 新增涩图 2022-01-01 23:36:12 +08:00
55da787d66 大头菜新增周日满背包价格 2021-12-26 10:25:07 +08:00
33c7f0df56 上次提交忘记加版本号了 2021-12-26 09:10:15 +08:00
66ae1c4e8b 调整天使动漫签到时间
修复大头菜不记录上周趋势的BUG
调整汇报大头菜结果时加入网页地址
2021-12-26 09:08:54 +08:00
e0751972a3 修复路由器扫描问题 2021-12-20 17:52:28 +08:00
59477d518a 完善开门接口 2021-12-20 17:34:23 +08:00
e7719b6cfe update 2021-12-20 01:01:07 +08:00
b430143037 update 2021-12-20 00:59:16 +08:00
edfddd7e17 预备开门页面及接口 2021-12-20 00:47:02 +08:00
a73a5b34e2 update 2021-12-18 17:38:43 +08:00
618f91457f 新增接口重启机器人 2021-12-18 17:33:14 +08:00
e2432b5942 修复通知时间会卡主的问题
修复重复获取路由器状态问题
2021-12-18 17:23:12 +08:00
7b1050b4e3 调整时间通知为每秒
新增wifi设备连入退出判断
为下发开门指令做准备
2021-12-16 23:25:05 +08:00
d35431a35d fix 2021-12-14 08:46:57 +08:00
159a437853 优化天使动漫签到 2021-12-14 01:53:17 +08:00
5a29f7595b 新增手动签到
新增百合会签到
优化天使动漫签到
优化大头菜统计最高价日
修复大头菜第二周数据未清空
新增大头菜显示购入价功能
2021-12-13 18:10:50 +08:00
174 changed files with 79904 additions and 838 deletions

17
KFCFactory.json Normal file
View File

@@ -0,0 +1,17 @@
{
"8.9.63": {
"base_url": "http://192.168.31.88:7400",
"type": "fuqiuluo/unidbg-fetch-qsign",
"key": "114514"
},
"0.1.0": {
"base_url": "http://127.0.0.1:8888",
"type": "kiliokuara/magic-signer-guide",
"server_identity_key": "vivo50",
"authorization_key": "kfc"
},
"8.8.88": {
"base_url": "http://127.0.0.1:80",
"type": "TLV544Provider"
}
}

Binary file not shown.

0
mvnw vendored Normal file → Executable file
View File

155
pom.xml
View File

@@ -32,42 +32,30 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.mamoe</groupId>
<artifactId>mirai-core-jvm</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-jdk8</artifactId>
<version>1.5.2</version>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core-jvm</artifactId>
<version>1.5.2</version>
<version>1.6.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0-RC1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.4.7</version>
<version>4.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.22</version>
</dependency>
<dependency>
@@ -88,14 +76,132 @@
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
<version>4.7.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>4.7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-api -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>4.7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-remote-driver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-http-jdk-client</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.21.12</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.21.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections
-->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.brotli/dec -->
<dependency>
<groupId>org.brotli</groupId>
<artifactId>dec</artifactId>
<version>0.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<!-- jsoup HTML parser library @ https://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>com.baidubce</groupId>
<artifactId>qianfan</artifactId>
<version>0.1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.24.1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
<build>
@@ -114,7 +220,9 @@
<configuration>
<tasks>
<echo>复制正式文件</echo>
<copy file="src/main/resources/application.properties.release" tofile="${project.build.outputDirectory}/application.properties" overwrite="true"/>
<copy file="src/main/resources/application.properties.release"
tofile="${project.build.outputDirectory}/application.properties"
overwrite="true"/>
</tasks>
</configuration>
</execution>
@@ -149,6 +257,7 @@
<!--使用-Dloader.path需要在打包的时候增加<layout>ZIP</layou
t>,不指定的话-Dloader.path不生效-->
<layout>ZIP</layout>
<includeSystemScope>true</includeSystemScope>
<!-- 指定该jar包启动时的主类[建议] -->
<mainClass>com.yutou.qqbot.QQBotApplication</mainClass>
</configuration>
@@ -159,12 +268,6 @@
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>
X:\servier\qqbot\
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

View File

@@ -0,0 +1,8 @@
package com.yutou.bilibili;
public class BaseAPI {
public static final String BASE_URL = "https://api.bilibili.com/";
public static final String MCBBS_PNG = "https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png";
public static final String ACCESS_TOKEN = "https://passport.bilibili.com/login/app/third";
}

View File

@@ -0,0 +1,9 @@
package com.yutou.bilibili.api;
public class LiveAPI {
public static final String LIVE_SEND_DANMU="https://api.live.bilibili.com/msg/send";
public static final String LIVE_ROOM_INFO = "https://api.live.bilibili.com/room/v1/Room/get_info";
public static final String LIVE_TASK_PROGRESS = "https://api.live.bilibili.com/xlive/app-ucenter/v1/userTask/GetUserTaskProgress";
public static final String LIVE_SET_TASK_PROGRESS = "https://api.live.bilibili.com/xlive/app-ucenter/v1/userTask/UserTaskReceiveRewards";
}

View File

@@ -0,0 +1,7 @@
package com.yutou.bilibili.api;
public class LoginAPI {
public static final String LOGIN_QRCODE = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate";
public static final String LOGIN_QRCODE_POLL="https://passport.bilibili.com/x/passport-login/web/qrcode/poll";
}

View File

@@ -0,0 +1,9 @@
package com.yutou.bilibili.api;
public class MangaApi {
public static final String SIGN = "https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn";
public static final String LIST_PRODUCT_DATE = "https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct";
public static final String USER_POINT = "https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint";
public static final String PAY_MISSION = "https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange";
}

View File

@@ -0,0 +1,7 @@
package com.yutou.bilibili.api;
public class SignApi {
public static final String LIVE_SIGN_COIN = "https://api.live.bilibili.com/xlive/revenue/v1/wallet/silver2coin";
public static final String LIVE_SIGN = "https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/DoSign";
public static final String VIP_SIGN = "https://api.bilibili.com/pgc/activity/score/task/sign";
}

View File

@@ -0,0 +1,10 @@
package com.yutou.bilibili.api;
public class UserApi {
@Deprecated
public static final String USER_INFO = "https://api.bilibili.com/x/space/acc/info";
public static final String USER_INFO_V2="https://api.bilibili.com/x/space/wbi/acc/info";
public static final String NAV = "https://api.bilibili.com/x/web-interface/nav";
}

View File

@@ -0,0 +1,6 @@
package com.yutou.bilibili.api;
public class VideoApi {
public static final String VIDEO_AI = "https://api.bilibili.com/x/web-interface/view/conclusion/get";
}

View File

@@ -0,0 +1,65 @@
package com.yutou.napcat;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.enums.MessageEnum;
import com.yutou.napcat.event.MessageEvent;
import com.yutou.napcat.handle.*;
import com.yutou.napcat.model.*;
import com.yutou.okhttp.HttpCallback;
import com.yutou.napcat.http.NapCatApi;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.utlis.Base64Tools;
import lombok.val;
import okhttp3.Headers;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NapCatQQ {
private NapCatQQ() {
}
public static void main(String[] args) {
/* List<BaseHandle<?>> list = new ArrayList<>();
list.add(new Text("1", false));
list.add(new Text("2", false));
list.add(new Text("3"));
list.add(new Text("4", false));
list.add(new At(583819556L));
list.add(new Text("5"));
QQBotManager.getInstance().sendMessage(false, 891655174L, list);*/
NapCatApi.setLog(false);
File file = new File("C:\\Users\\58381\\Downloads\\0074TT8Yly1hp5mqidwqeg30g20f27wh.gif");
NapCatApi.getMessageApi().sendPrivateMsg(
MessageHandleBuild.create()
.setQQNumber(583819556L)
//.add(new Image(file))
.add(new Text("abc"))
.build()
).enqueue(new HttpCallback<SendMessageResponse>() {
@Override
public void onResponse(Headers headers, int code, String status, SendMessageResponse response, String rawResponse) {
System.out.println("code = " + code + ", status = " + status + ", response = " + response + ", rawResponse = " + rawResponse);
}
@Override
public void onFailure(Throwable throwable) {
throwable.printStackTrace();
}
});
}
/**
* 私聊
{"self_id":240828363,"user_id":583819556,"time":1714472684,"message_id":376,"real_id":376,"message_type":"private","sender":{"user_id":583819556,"nickname":"魔芋","card":""},"raw_message":"123","font":14,"sub_type":"friend","message":[{"data":{"text":"123"},"type":"text"}],"message_format":"array","post_type":"message"}
*/
/**
* 群聊
* {"self_id":240828363,"user_id":583819556,"time":1714472695,"message_id":377,"real_id":377,"message_type":"group","sender":{"user_id":583819556,"nickname":"魔芋","card":"","role":"owner"},"raw_message":"222","font":14,"sub_type":"normal","message":[{"data":{"text":"222"},"type":"text"}],"message_format":"array","post_type":"message","group_id":891655174}
*/
}

View File

@@ -0,0 +1,54 @@
package com.yutou.napcat;
import com.yutou.napcat.model.FriendBean;
import com.yutou.napcat.model.GroupBean;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class QQDatabase {
private static Map<Long, Object> data = new HashMap<>();
@Getter
@Setter
private static FriendBean me;
public static void addUser(Long qq, FriendBean bean) {
data.put(qq, bean);
}
public static void addGroup(Long qq, GroupBean bean) {
data.put(qq, bean);
}
public static boolean checkFriend(Long qq) {
if (data.containsKey(qq)) {
return data.get(qq) instanceof FriendBean;
}
return false;
}
public static boolean checkGroup(Long qq) {
if (data.containsKey(qq)) {
return data.get(qq) instanceof GroupBean;
}
return false;
}
public static List<GroupBean> getGroups() {
List<GroupBean> numbers = new ArrayList<>();
for (Long qq : data.keySet()) {
if (data.get(qq) instanceof GroupBean) {
{
numbers.add((GroupBean) data.get(qq));
}
}
}
return numbers;
}
}

View File

@@ -0,0 +1,29 @@
package com.yutou.napcat.enums;
public enum MessageEnum {
TEXT("text"),
IMAGE("image"),
AT("at"),
REPLY("reply"),
JSON("json");
String type;
MessageEnum(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static MessageEnum of(String type) {
for (MessageEnum messageEnum : MessageEnum.values()) {
if (messageEnum.getType().equals(type)) {
return messageEnum;
}
}
return null;
}
}

View File

@@ -0,0 +1,28 @@
package com.yutou.napcat.enums;
public enum RecordFormatEnum {
MP3("mp3"),
AMR("amr"),
WMA("wma"),
M4A("m4a"),
SPX("spx"),
OGG("ogg"),
WAV("wav"),
FLAC("flac");
private final String format;
RecordFormatEnum(String format) {
this.format = format;
}
public String getFormat() {
return format;
}
@Override
public String toString() {
return format;
}
}

View File

@@ -0,0 +1,13 @@
package com.yutou.napcat.event;
import com.yutou.napcat.model.GroupFrom;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class GroupMessageEvent extends MessageEvent {
private GroupFrom group;
}

View File

@@ -0,0 +1,198 @@
package com.yutou.napcat.event;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap;
import com.yutou.napcat.QQDatabase;
import com.yutou.napcat.enums.MessageEnum;
import com.yutou.napcat.handle.*;
import com.yutou.napcat.model.AppShareBean;
import com.yutou.napcat.model.Message;
import com.yutou.napcat.model.SourceFrom;
import lombok.Data;
import lombok.val;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Data
public class MessageEvent {
@JSONField(name = "self_id")
private Long selfId;
@JSONField(name = "user_id")
private Long userId;
@JSONField(name = "time")
private Long time;
@JSONField(name = "message_id")
private Integer messageId;
@JSONField(name = "real_id")
private Integer realId;
@JSONField(name = "message_type")
private String messageType;
@JSONField(name = "sender")
private SourceFrom source;
@JSONField(name = "raw_message")
private String rawMessage;
@JSONField(name = "font")
private Integer font;
@JSONField(name = "sub_type")
private String subType;
@JSONField(name = "message")
private List<BaseHandle<?>> message;
@JSONField(name = "message_format")
private String messageFormat;
@JSONField(name = "post_type")
private String postType;
@JSONField(name = "group_id")
private Long groupId;
public static MessageEvent parseHandleHttp(String jsonString) {
return parseHandle(JSONObject.parseObject(jsonString).getJSONObject("data").toString());
}
public static MessageEvent parseHandle(String jsonString) {
JSONObject json = JSONObject.parseObject(jsonString);
JSONArray array = json.getJSONArray("message");
List<BaseHandle<?>> messageList = new ArrayList<>();
if (array != null) {
for (Object o : array) {
JSONObject _json = (JSONObject) o;
Type classType = null;
MessageEnum _type = MessageEnum.of(_json.getString("type"));
classType = switch (_type) {
case TEXT -> Text.TextInfo.class;
case IMAGE -> Image.ImageInfo.class;
case AT -> At.AtData.class;
case JSON -> OtherHandle.OtherInfo.class;
case REPLY -> Reply.ReplyInfo.class;
default -> classType;
};
BaseHandle<?> handle = new BaseHandle<>(_type.getType());
if (_type == MessageEnum.JSON) {
handle.setData(JSONObject.parseObject(((JSONObject) o).getJSONObject("data").getString("data"), classType));
} else {
handle.setData(JSONObject.parseObject(((JSONObject) o).getJSONObject("data").toString(), classType));
}
messageList.add(handle);
}
}
MessageEvent event = new MessageEvent();
event.setTime(json.getLong("time"));
event.setSelfId(json.getLong("self_id"));
event.setPostType(json.getString("post_type"));
event.setGroupId(json.getLong("group_id"));
event.setUserId(json.getLong("user_id"));
event.setSubType(json.getString("sub_type"));
try {
SourceFrom sender = new SourceFrom();
sender.setUserId(event.getUserId());
event.setSource(sender);
sender.setUserId(json.getJSONObject("sender").getLong("user_id"));
sender.setNickname(json.getJSONObject("sender").getString("nickname"));
sender.setRole(json.getJSONObject("sender").getString("role"));
sender.setCard(json.getJSONObject("sender").getString("card"));
event.setMessageId(json.getInteger("message_id"));
event.setRealId(json.getInteger("real_id"));
event.setMessageType(json.getString("message_type"));
event.setSource(sender);
event.setRawMessage(json.getString("raw_message"));
event.setFont(json.getInteger("font"));
event.setMessageFormat(json.getString("message_format"));
event.setMessage(messageList);
return event;
} catch (Exception e) {
System.err.println("jsonString:\n" + jsonString);
}
return event;
}
public boolean hasType(MessageEnum messageEnum) {
if(message==null||message.isEmpty()){
return false;
}
for (BaseHandle<?> handle : message) {
if (MessageEnum.of(handle.getType()) == messageEnum) {
return true;
}
}
return false;
}
public <T extends BaseHandle> List<T> findAllType(Class<T> t) {
List<T> tmp = new ArrayList<>();
if (message == null || message.isEmpty()) {
return tmp;
}
try {
T newed = t.getDeclaredConstructor().newInstance();
for (BaseHandle<?> baseHandle : message) {
if (baseHandle.getType().equals(newed.getType())) {
newed.setData(baseHandle.getData());
tmp.add(newed);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return tmp;
}
public <T extends BaseHandle> T findType(Class<T> tClass) {
List<T> list = findAllType(tClass);
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
public boolean isAtMe() {
if (!hasType(MessageEnum.AT)) {
return false;
}
List<At> list = findAllType(At.class);
for (At handle : list) {
if (handle.getData().getQq() == QQDatabase.getMe().getUserId()) {
return true;
}
}
return false;
}
public String getTextMessage() {
val texts = findAllType(Text.class);
StringBuilder sb = new StringBuilder();
for (Text text : texts) {
sb.append(text);
}
return sb.toString().trim();
}
public boolean isUser() {
return "private".equals(messageType);
}
public boolean isGroup() {
return "group".equals(messageType);
}
}

View File

@@ -0,0 +1,32 @@
package com.yutou.napcat.handle;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
public class At extends BaseHandle<At.AtData> {
public At() {
super("at");
}
public At(Long userId) {
super("at");
data = new AtData(userId);
}
@Override
public String toString() {
if (data == null) {
return null;
}
return String.format("[CQ:at,qq=%d]", data.qq);
}
@Data
public class AtData extends BaseBean {
private Long qq;
public AtData(Long qq) {
this.qq = qq;
}
}
}

View File

@@ -0,0 +1,28 @@
package com.yutou.napcat.handle;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.enums.MessageEnum;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
@Data
public class BaseHandle<T> extends BaseBean {
protected String type;
protected T data;
protected String src;
public BaseHandle(String type) {
this.type = type;
}
public BaseHandle(String type, Object obj) {
super();
this.type = type;
this.data= (T) obj;
}
}

View File

@@ -0,0 +1,35 @@
package com.yutou.napcat.handle;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.qqbot.utlis.Base64Tools;
import lombok.Data;
import java.io.File;
public class Image extends BaseHandle<Image.ImageInfo> {
public Image() {
super("image");
}
public Image(String imageUrl) {
super("image");
data = new ImageInfo(imageUrl);
}
public Image(File imageFile){
super("image");
data=new ImageInfo("base64://"+ Base64Tools.encode(imageFile));
}
@Data
public static class ImageInfo {
String file;
String url;
@JSONField(name = "file_size")
String fileSize;
public ImageInfo(String file) {
this.file = file;
}
}
}

View File

@@ -0,0 +1,64 @@
package com.yutou.napcat.handle;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.okhttp.BaseBean;
import com.yutou.qqbot.utlis.StringUtils;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
public class MessageHandleBuild {
private List<BaseHandle<?>> msgList = new ArrayList<>();
private long qq;
private boolean autoEscape;
private boolean isGroup;
private String messageId;
public static MessageHandleBuild create() {
return new MessageHandleBuild();
}
private MessageHandleBuild() {
msgList = new ArrayList<>();
}
public MessageHandleBuild setQQNumber(long qq) {
this.qq = qq;
return this;
}
public MessageHandleBuild setAutoEscape(boolean autoEscape) {
this.autoEscape = autoEscape;
return this;
}
public MessageHandleBuild add(BaseHandle<?> msg) {
msgList.add(msg);
return this;
}
public MessageHandleBuild setGroup(boolean group) {
isGroup = group;
return this;
}
public MessageHandleBuild setMessageId(String messageId) {
this.messageId = messageId;
return this;
}
public JSONObject build() {
JSONObject json=new JSONObject();
if(isGroup){
json.put("group_id", qq);
}else {
json.put("user_id", qq);
}
json.put("auto_escape", autoEscape);
json.put("message", msgList);
if(!StringUtils.isEmpty(messageId)){
json.put("message_id",messageId);
}
return json;
}
}

View File

@@ -0,0 +1,20 @@
package com.yutou.napcat.handle;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.model.AppShareBean;
import lombok.Data;
public class OtherHandle extends BaseHandle<OtherHandle.OtherInfo>{
public OtherHandle() {
super("json");
data= new OtherInfo();
}
@Data
public static class OtherInfo extends AppShareBean{
}
}

View File

@@ -0,0 +1,14 @@
package com.yutou.napcat.handle;
public class QuoteReply {
private final String messageId;
public QuoteReply(String messageId) {
this.messageId = messageId;
}
@Override
public String toString() {
return String.format("[CQ:reply,id=%s]",messageId);
}
}

View File

@@ -0,0 +1,38 @@
package com.yutou.napcat.handle;
import com.yutou.qqbot.utlis.ConfigTools;
import lombok.Data;
public class Record extends BaseHandle<Record.RecordInfo> {
public Record() {
super("record");
}
public Record(String file) {
super("record");
data = new RecordInfo(file);
}
public Record(String file, boolean proxy) {
super("record");
data = new RecordInfo(file);
data.proxy = proxy ? "1" : "0";
}
@Data
public static class RecordInfo {
String file;
int magic;
String url;
String cache;
String proxy;
String timeout;
public RecordInfo(String file) {
this.file = ConfigTools.getServerUrl()+file;
}
}
}

View File

@@ -0,0 +1,24 @@
package com.yutou.napcat.handle;
import lombok.Data;
public class Reply extends BaseHandle<Reply.ReplyInfo> {
public Reply() {
super("reply");
}
public Reply(long id) {
super("reply");
data = new ReplyInfo(id);
}
@Data
public static class ReplyInfo {
private long id;
public ReplyInfo(long id) {
this.id = id;
}
}
}

View File

@@ -0,0 +1,53 @@
package com.yutou.napcat.handle;
import lombok.Data;
import java.lang.reflect.Type;
public class Text extends BaseHandle<Text.TextInfo> {
public Text() {
super("text");
}
public Text(String text) {
super("text");
data = new TextInfo(text + "\n");
}
public Text(String text, boolean isNewLine) {
super("text");
if (isNewLine) {
data = new TextInfo(text + "\n");
} else {
data = new TextInfo(text);
}
}
public Text(boolean isNewLine, String... text) {
super("text");
StringBuilder sb = new StringBuilder();
for (String s : text) {
sb.append(s);
}
if (isNewLine) {
data = new TextInfo(sb + "\n");
} else {
data = new TextInfo(sb.toString());
}
}
@Override
public String toString() {
return data.text.trim();
}
@Data
public static class TextInfo {
String text;
public TextInfo(String text) {
this.text = text.trim();
}
}
}

View File

@@ -0,0 +1,17 @@
package com.yutou.napcat.http;
import com.yutou.napcat.model.FriendBean;
import com.yutou.okhttp.BaseBean;
import com.yutou.okhttp.HttpBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
import java.util.List;
public interface FriendApi {
@POST("/get_friend_list")
Call<HttpBody<List<FriendBean>>> getFriendList(
);
}

View File

@@ -0,0 +1,86 @@
package com.yutou.napcat.http;
import com.yutou.napcat.model.FriendBean;
import com.yutou.napcat.model.GroupBean;
import com.yutou.napcat.model.GroupUserBean;
import com.yutou.okhttp.BaseBean;
import com.yutou.okhttp.HttpBody;
import retrofit2.Call;
import retrofit2.http.*;
import java.util.List;
public interface GroupApi {
/**
* 禁言
*
* @param group 群号
* @param user 用户
* @param duration 禁言时长,单位秒
*/
@GET("/set_group_ban")
Call<HttpBody<BaseBean>> groupBan(
@Query("group_id") long group,
@Query("user_id") long user,
@Query("duration") long duration
);
/**
* 禁言群组全体成员
*
* @param group 群号
*/
@FormUrlEncoded
@POST("/set_group_whole_ban")
Call<HttpBody<BaseBean>> groupBanAll(
@Field("group_id") long group
);
/**
* 获取群组列表
*/
@POST("/get_group_list")
Call<HttpBody<List<GroupBean>>> getGroupList(
);
/**
* 获取群组信息
*/
@POST("/get_group_info")
Call<HttpBody<GroupBean>> getGroupInfo(
);
/**
* 获取群组成员信息
*/
@POST("/get_group_member_info")
Call<HttpBody<GroupUserBean>> getGroupUserInfo(
);
/**
* 获取群组成员列表
*
* @param group 群号
*/
@FormUrlEncoded
@POST("/get_group_member_list")
Call<HttpBody<List<GroupUserBean>>> getGroupUserList(
@Field("group_id") long group,
@Field("no_cache")boolean noCache
);
/**
* 设置群组专属头衔
* @param group 群号
* @param user 用户
* @param title 头衔
* @param duration 持续时间,单位秒
*/
@POST("/set_group_special_title")
@FormUrlEncoded
Call<HttpBody<BaseBean>> setGroupSpecialTitle(
@Field("group_id") long group,
@Field("user_id") long user,
@Field("special_title") String title,
@Field("duration") long duration );
}

View File

@@ -0,0 +1,52 @@
package com.yutou.napcat.http;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.handle.BaseHandle;
import com.yutou.napcat.model.MessageBean;
import com.yutou.napcat.model.SendMessageResponse;
import com.yutou.okhttp.BaseBean;
import com.yutou.okhttp.HttpBody;
import kotlin.jvm.JvmSuppressWildcards;
import retrofit2.Call;
import retrofit2.http.*;
import java.util.List;
public interface MessageAPI {
/**
* 发送私聊消息
* @param message {@link com.yutou.napcat.handle.MessageHandleBuild}
* @return 消息id
*/
@POST("/send_private_msg")
Call<HttpBody<SendMessageResponse>> sendPrivateMsg(
@Body
JSONObject message);
/**
* 发送群聊消息
* @param message 消息内容
* @return 消息id
*/
@POST("/send_group_msg")
Call<HttpBody<SendMessageResponse>> sendGroupMsg(
@Body
JSONObject message
);
/**
* 撤回消息
* @param messageId 消息id
*/
@FormUrlEncoded
@POST("/delete_msg")
Call<HttpBody<BaseBean>> delMsg(
@Field("message_id") long messageId
);
@POST("/get_msg")
Call<HttpBody<MessageBean>> getMessage(
@Body
JSONObject message
);
}

View File

@@ -0,0 +1,29 @@
package com.yutou.napcat.http;
import com.yutou.okhttp.HttpLoggingInterceptor;
import com.yutou.okhttp.api.BaseApi;
import com.yutou.qqbot.utlis.ConfigTools;
public class NapCatApi extends BaseApi {
private static final String URL;
static {
URL= ConfigTools.load(ConfigTools.CONFIG,ConfigTools.NAPCAT_URL,String.class);
}
public static void setLog(boolean log){
HttpLoggingInterceptor.setLog(log);
}
public static MessageAPI getMessageApi(){
return new NapCatApi().setURL(URL).createApi(MessageAPI.class);
}
public static UtilsApi getUtilsApi(){
return new NapCatApi().setURL(URL).createApi(UtilsApi.class);
}
public static GroupApi getGroupApi(){
return new NapCatApi().setURL(URL).createApi(GroupApi.class);
}
public static FriendApi getFriendApi(){
return new NapCatApi().setURL(URL).createApi(FriendApi.class);
}
}

View File

@@ -0,0 +1,80 @@
package com.yutou.napcat.http;
import com.yutou.napcat.model.*;
import com.yutou.okhttp.BaseBean;
import com.yutou.okhttp.HttpBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface UtilsApi {
/**
* 获取语音
*
* @param fileId 收到的语音文件名(消息段的 file 参数),如 0B38145AA44505000B38145AA4450500.silk
* @param format 要转换到的格式,目前支持 mp3、amr、wma、m4a、spx、ogg、wav、flac {@link com.yutou.napcat.enums.RecordFormatEnum}
* @return 转换后的语音文件路径
*/
@FormUrlEncoded
@POST("/get_record")
Call<HttpBody<String>> getMessageRecord(
@Field("file") String fileId,
@Field("out_format") String format
);
/**
* 获取图片
*
* @param fileId 收到的图片文件名(消息段的 file 参数)
* @return 下载后的图片文件路径
*/
@FormUrlEncoded
@POST("/get_image")
Call<HttpBody<String>> getMessageImage(
@Field("file") String fileId
);
/**
* 检查是否可以发送图片
*/
@POST("/can_send_image")
Call<HttpBody<CheckSendImageBean>> checkSendImage(
);
/**
* 检查是否可以发送语音
*/
@POST("/can_send_record")
Call<HttpBody<CheckSendRecordBean>> checkSendRecord(
);
/**
* 获取机器人状态
*/
@POST("/get_status")
Call<HttpBody<QQBotStatusBean>> checkQQBotStatus(
);
/**
* 获取机器人版本信息
*/
@POST("/get_version_info")
Call<HttpBody<QQBotVersionBean>> checkQQBotVersion(
);
/**
* 清理缓存
*/
@POST("/clean_cache")
Call<HttpBody<BaseBean>> cleanCache(
);
/**
* 获取登录信息
*/
@POST("/get_login_info")
Call<HttpBody<FriendBean>> getLoginInfo(
);
}

View File

@@ -0,0 +1,139 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
import java.util.Map;
@Data
public class AppShareBean extends BaseBean {
@JSONField(name = "ver")
private String version;
@JSONField(name = "prompt")
private String prompt;
@JSONField(name = "config")
private Config config;
@JSONField(name = "needShareCallBack")
private boolean needShareCallBack;
@JSONField(name = "app")
private String app;
@JSONField(name = "view")
private String view;
@JSONField(name = "meta")
private Meta meta;
// getters and setters...
// Inner classes
@Data
public static class Config {
@JSONField(name = "type")
private String type;
@JSONField(name = "width")
private int width;
@JSONField(name = "height")
private int height;
@JSONField(name = "forward")
private int forward;
@JSONField(name = "autoSize")
private int autoSize;
@JSONField(name = "ctime")
private long ctime;
@JSONField(name = "token")
private String token;
// getters and setters...
}
@Data
public static class Meta {
@JSONField(name = "detail_1")
private Detail detail1;
// If there can be multiple "detail_X" entries, you might need a Map
// @JSONField(name = "detail_X")
// private Map<String, Detail> details;
// getters and setters...
}
@Data
public static class Detail {
@JSONField(name = "appid")
private String appid;
@JSONField(name = "appType")
private int appType;
@JSONField(name = "title")
private String title;
@JSONField(name = "desc")
private String desc;
@JSONField(name = "icon")
private String icon;
@JSONField(name = "preview")
private String preview;
@JSONField(name = "url")
private String url;
@JSONField(name = "scene")
private int scene;
@JSONField(name = "host")
private Host host;
@JSONField(name = "shareTemplateId")
private String shareTemplateId;
// Since "shareTemplateData" is an empty object, it can be left as a Map or a specific class
// if you know the structure of the data that might be there
@JSONField(name = "shareTemplateData")
private Map<String, Object> shareTemplateData;
@JSONField(name = "qqdocurl")
private String qqdocurl;
@JSONField(name = "showLittleTail")
private String showLittleTail;
@JSONField(name = "gamePoints")
private String gamePoints;
@JSONField(name = "gamePointsUrl")
private String gamePointsUrl;
// getters and setters...
}
@Data
public static class Host {
@JSONField(name = "uin")
private long uin;
@JSONField(name = "nick")
private String nick;
// getters and setters...
}
}

View File

@@ -0,0 +1,12 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class CheckSendImageBean extends BaseBean {
@JSONField(name = "yes")
private boolean yes;
}

View File

@@ -0,0 +1,12 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class CheckSendRecordBean extends BaseBean {
@JSONField(name = "yes")
private boolean yes;
}

View File

@@ -0,0 +1,15 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class FriendBean extends BaseBean {
@JSONField(name = "user_id")
private long userId;//qq号
@JSONField(name = "nickname")
private String nickName;//昵称
@JSONField(name = "remark")
private String remark;//备注
}

View File

@@ -0,0 +1,18 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class GroupBean extends BaseBean {
@JSONField(name = "group_id")
private long groupId;
@JSONField(name = "group_name")
private String groupName;
@JSONField(name = "member_count")
private int userCount;
@JSONField(name = "max_member_count")
private int userMaxCount;
}

View File

@@ -0,0 +1,8 @@
package com.yutou.napcat.model;
import lombok.Data;
@Data
public class GroupFrom {
private long id;
}

View File

@@ -0,0 +1,72 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class GroupUserBean extends BaseBean {
// 群号
@JSONField(name = "group_id")
private long groupId;
// QQ号
@JSONField(name = "user_id")
private long userId;
// 昵称
@JSONField(name = "nickname")
private String nickname;
// 群名片/备注
@JSONField(name = "card")
private String card;
// 性别male 或 female 或 unknown
@JSONField(name = "sex")
private String sex;
// 年龄
@JSONField(name = "age")
private int age;
// 地区
@JSONField(name = "area")
private String area;
// 加群时间戳
@JSONField(name = "join_time")
private int joinTime;
// 最后发言时间戳
@JSONField(name = "last_sent_time")
private int lastSentTime;
// 成员等级
@JSONField(name = "level")
private String level;
// 角色owner 或 admin 或 member
@JSONField(name = "role")
private String role;
// 是否不良记录成员
@JSONField(name = "unfriendly")
private boolean unfriendly;
// 专属头衔
@JSONField(name = "title")
private String title;
// 专属头衔过期时间戳
@JSONField(name = "title_expire_time")
private int titleExpireTime;
// 是否允许修改群名片
@JSONField(name = "card_changeable")
private boolean cardChangeable;
// 禁言剩余时间
@JSONField(name = "shut_up_timestamp")
private long shutUpTimestamp;
}

View File

@@ -0,0 +1,23 @@
package com.yutou.napcat.model;
import lombok.Data;
@Data
public class Message {
private String message;
private String srcMessage;
private String id;
public Message(String message, String srcMessage) {
this.message = message;
this.srcMessage = srcMessage;
}
public String serializeToMiraiCode(){
return srcMessage;
}
public String contentToString(){
return message;
}
}

View File

@@ -0,0 +1,50 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.napcat.event.MessageEvent;
import com.yutou.napcat.handle.BaseHandle;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
import java.lang.reflect.Type;
/**
* 消息
* @see <a href="https://github.com/botuniverse/onebot-11/blob/master/api/public.md#get_msg-%E8%8E%B7%E5%8F%96%E6%B6%88%E6%81%AF">文档</a>
*/
@Data
public class MessageBean extends BaseBean {
/**
*发送时间
*/
@JSONField(name = "time")
private long time;
/**
* 消息类型,同 <a href="https://github.com/botuniverse/onebot-11/blob/master/event/message.md">消息事件</a>
*/
@JSONField(name = "message_type")
private String type;
/**
* 消息 ID
*/
@JSONField(name = "message_id")
private int messageId;
/**
* 消息真实 ID
*/
@JSONField(name = "real_id")
private int realId;
/**
* 发送人信息,同 <a href="https://github.com/botuniverse/onebot-11/blob/master/event/message.md">消息事件</a>
*/
@JSONField(name = "sender")
private SenderBean sender;
/**
* 消息内容
*/
@JSONField(name = "message")
private String message;
}

View File

@@ -0,0 +1,13 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
@Data
public class QQBotStatusBean extends BaseBean {
@JSONField(name = "online")
private String online;//当前 QQ 在线null 表示无法查询到在线状态
@JSONField(name = "good")
private String good;//状态符合预期,意味着各模块正常运行、功能正常,且 QQ 在线
}

View File

@@ -0,0 +1,17 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
@Data
public class QQBotVersionBean {
@JSONField(name = "app_name")
private String appName;//应用标识,如 mirai-native
@JSONField(name = "app_version")
private String appVersion;//应用版本,如 1.2.3
@JSONField(name = "protocol_version")
private String protocolVersion;//OneBot 标准版本,如 v11
}

View File

@@ -0,0 +1,21 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.google.gson.annotations.SerializedName;
import com.yutou.napcat.handle.BaseHandle;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class SendMessageRequest extends BaseBean {
@JSONField(name = "user_id")
private long userId;
@JSONField
List<BaseHandle<?>> message;
@SerializedName("auto_escape")
private boolean notCQCode;
}

View File

@@ -0,0 +1,17 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.google.gson.annotations.SerializedName;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class SendMessageResponse extends BaseBean {
@JSONField( name = "message_id")
private int id;
private String e;
}

View File

@@ -0,0 +1,24 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.yutou.okhttp.BaseBean;
import lombok.Data;
/**
* 发送人结构体
*
*/
@Data
public class SenderBean extends BaseBean {
@JSONField(name = "user_id")
private long userId;
@JSONField(name = "nickname")
private String nickName;
/**
* male 或 female 或 unknown
*/
@JSONField(name = "sex")
private String sex;
@JSONField(name = "age")
private int age;
}

View File

@@ -0,0 +1,21 @@
package com.yutou.napcat.model;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
@Data
public class SourceFrom {
public static final String USER_ROLE_OWNER="owner";//群主
public static final String USER_ROLE_ADMIN="admin";//管理
public static final String USER_ROLE_MEMBER="member";//成员
@JSONField(name = "user_id")
private long userId;
private String nickname;
private String card;
@JSONField(name = "role")
private String role;
public Long getFromId() {
return userId;
}
}

View File

@@ -0,0 +1,6 @@
package com.yutou.okhttp;
import java.io.Serializable;
public class BaseBean implements Serializable {
}

View File

@@ -0,0 +1,11 @@
package com.yutou.okhttp;
import lombok.Data;
import java.io.InputStream;
@Data
public class FileBody<T> {
InputStream inputStream;
T t;
}

View File

@@ -0,0 +1,112 @@
package com.yutou.okhttp;
import com.yutou.qqbot.utlis.Log;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public abstract class FileCallback<T> implements Callback<FileBody<T>> {
private static ThreadPoolExecutor executor;
private final T bean;
private String savePath;
public FileCallback(T bean, String savePath) {
this.bean = bean;
this.savePath = savePath;
if (executor == null) {
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
}
}
private class DownloadTask implements Runnable {
private T bean;
private Headers headers;
private HttpUrl url;
private InputStream inputStream;
public DownloadTask(T bean, Headers headers, HttpUrl url, InputStream inputStream) {
this.bean = bean;
this.headers = headers;
this.url = url;
this.inputStream = inputStream;
}
@Override
public void run() {
try {
Log.i("开始下载");
File file = new File(savePath);
onStart(bean);
if (!file.exists()) {
boolean mkdirs = file.getParentFile().mkdirs();
Log.i("mkdirs = " + mkdirs);
}
FileOutputStream outputStream = new FileOutputStream(file);
int len;
long total = 0;
byte[] bytes = new byte[4096];
boolean isDownload = true;
long available = inputStream.available();
while ((len = inputStream.read(bytes)) != -1 && isDownload) {
total += len;
outputStream.write(bytes, 0, len);
outputStream.flush();
isDownload = onDownload(headers, bean, total, available);
}
Log.i("下载完成");
outputStream.close();
} catch (Exception e) {
Log.e(e);
onFailure(bean,e);
} finally {
onFinish(bean);
try {
inputStream.close();
} catch (IOException e) {
Log.e(e);
}
}
}
}
public abstract void onStart(T bean);
public abstract boolean onDownload(Headers headers, T bean, long len, long total);
public abstract void onFinish(T bean);
public abstract void onFailure(T bean, Throwable throwable);
@Override
public void onResponse(Call<FileBody<T>> call, Response<FileBody<T>> response) {
try {
executor.execute(new DownloadTask(bean, response.headers(), call.request().url(), response.body().getInputStream()));
} catch (Exception e) {
Log.e(e);
onFailure(bean,e);
call.cancel();
}
}
@Override
public void onFailure(Call<FileBody<T>> call, Throwable throwable) {
onFailure(bean, throwable);
call.cancel();
}
}

View File

@@ -0,0 +1,32 @@
package com.yutou.okhttp;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Request;
import java.util.HashMap;
public class GetRequestParams implements IRequestParam {
/**
* 构建Request
*
* @param request
* @return
*/
@Override
public Request getRequest(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
Headers.Builder headerBuild = request.headers().newBuilder();
if (!headerMap.isEmpty()) {
for (String key : headerMap.keySet()) {
headerBuild.add(key, headerMap.get(key));
}
}
//添加公共参数
HttpUrl.Builder builder = request.url().newBuilder();
for (String key : map.keySet()) {
builder.addQueryParameter(key, String.valueOf(map.get(key)));
}
return request.newBuilder().url(builder.build()).headers(headerBuild.build()).build();
}
}

View File

@@ -0,0 +1,14 @@
package com.yutou.okhttp;
import lombok.Data;
@Data
public class HttpBody<T> {
private String msg;
private String status;
private int code;
private int retcode;
private T data;
private String src;
}

View File

@@ -0,0 +1,35 @@
package com.yutou.okhttp;
import okhttp3.Headers;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public abstract class HttpCallback<T> implements Callback<HttpBody<T>> {
public abstract void onResponse(Headers headers,int code, String status, T response, String rawResponse);
public abstract void onFailure(Throwable throwable);
@Override
public void onResponse(Call<HttpBody<T>> call, Response<HttpBody<T>> response) {
if (response.body() != null) {
onResponse(
response.headers(),
response.body().getRetcode(),
response.body().getStatus(),
response.body().getData(),
response.body().getSrc()
);
} else {
onFailure(new NullPointerException("response body is null"));
}
call.cancel();
}
@Override
public void onFailure(Call<HttpBody<T>> call, Throwable throwable) {
onFailure(throwable);
call.cancel();
}
}

View File

@@ -0,0 +1,145 @@
package com.yutou.okhttp;
import com.yutou.qqbot.interfaces.DownloadInterface;
import com.yutou.qqbot.utlis.ConfigTools;
import com.yutou.qqbot.utlis.Log;
import lombok.Data;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class HttpDownloadUtils {
public static void download(Builder builder) {
createHttpClient(builder).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
if (builder.downloadInterface != null) {
builder.downloadInterface.onError(e);
}
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
File target;
if (StringUtils.hasText(builder.fileName)) {
target = new File(builder.path, builder.fileName);
} else {
target = new File(builder.path);
}
FileOutputStream fileOutputStream = new FileOutputStream(target);
if (builder.downloadInterface != null) {
builder.downloadInterface.onDownloadStart();
}
try {
byte[] buffer = new byte[2048];
int len;
long soFarBytes = 0;
long totalBytes = inputStream.available();
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
soFarBytes += len;
if (builder.downloadInterface != null) {
if (!builder.downloadInterface.onDownloading(soFarBytes, totalBytes)) {
break;
}
}
}
fileOutputStream.flush();
} catch (IOException e) {
Log.e(e,"download error:", builder.url);
} finally {
if (builder.downloadInterface != null) {
builder.downloadInterface.onDownload(target);
}
}
}
});
}
public static File downloadSync(Builder builder) {
try {
Response response = createHttpClient(builder).execute();
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
File target;
if (StringUtils.hasText(builder.fileName)) {
target = new File(builder.path, builder.fileName);
} else {
target = new File(builder.path);
}
try (FileOutputStream fileOutputStream = new FileOutputStream(target)) {
byte[] buffer = new byte[2048];
int len;
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.flush();
return target;
} catch (IOException e) {
Log.e(e,"download error:" , builder.url);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return null;
}
private static Call createHttpClient(Builder builder) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build();
Request.Builder rb = new Request.Builder()
.get()
.addHeader("User-Agent", ConfigTools.getUserAgent())
.url(builder.url);
if (StringUtils.hasText(builder.cookie)) {
rb.addHeader("Set-Cookie", builder.cookie);
rb.addHeader("Cookie", builder.cookie);
}
Request request = rb.build();
return okHttpClient.newCall(request);
}
@Data
public static class Builder {
String url;
String path;
String fileName;
DownloadInterface downloadInterface;
String cookie;
public Builder setUrl(String url) {
this.url = url;
return this;
}
public Builder setPath(String path) {
this.path = path;
return this;
}
public Builder setFileName(String fileName) {
this.fileName = fileName;
return this;
}
public Builder setDownloadInterface(DownloadInterface downloadInterface) {
this.downloadInterface = downloadInterface;
return this;
}
public Builder setCookie(String cookie) {
this.cookie = cookie;
return this;
}
}
}

View File

@@ -0,0 +1,216 @@
package com.yutou.okhttp;
import com.yutou.qqbot.utlis.Log;
import lombok.val;
import okhttp3.*;
import okhttp3.internal.http.HttpHeaders;
import okio.Buffer;
import okio.BufferedSource;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class HttpLoggingInterceptor implements Interceptor {
private static final String TAG = "HttpLogging";
private static final Charset UTF8 = StandardCharsets.UTF_8;
private volatile Level printLevel = Level.BODY;
private java.util.logging.Level colorLevel;
private Logger logger;
private static boolean prLog;
public static void setLog(boolean log) {
prLog = log;
}
public enum Level {
NONE, //不打印log
BASIC, //只打印 请求首行 和 响应首行
HEADERS, //打印请求和响应的所有 Header
BODY //所有数据全部打印
}
public HttpLoggingInterceptor(String tag) {
logger = Logger.getLogger(tag);
colorLevel = java.util.logging.Level.INFO;
}
public void setPrintLevel(Level level) {
if (printLevel == null)
throw new NullPointerException("printLevel == null. Use Level.NONE instead.");
printLevel = level;
}
public void setColorLevel(java.util.logging.Level level) {
colorLevel = level;
}
private void log(String message) {
//logger.log(colorLevel, message);
if (prLog) {
// Log.getDynamicLogger(TAG).info(message);
System.out.println(message);
}
//Log.e(TAG,message);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.body() != null && request.body().contentLength() == 0) {
val headers = request.headers();
request = chain.call().request().newBuilder()
.headers(headers)
.build();
}
if (printLevel == Level.NONE) {
return chain.proceed(request);
}
//请求日志拦截
logForRequest(request, chain.connection());
//执行请求,计算请求时间
long startNs = System.nanoTime();
Response response;
try {
response = chain.proceed(request);
} catch (Exception e) {
log("<-- HTTP FAILED: " + e);
throw e;
}
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
//响应日志拦截
return logForResponse(response, tookMs);
}
private void logForRequest(Request request, Connection connection) throws IOException {
boolean logBody = (printLevel == Level.BODY);
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
try {
String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol;
log(requestStartMessage);
if (logHeaders) {
if (hasRequestBody) {
if (requestBody.contentType() != null) {
log("\tContent-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
log("\tContent-Length: " + requestBody.contentLength());
}
}
Headers headers = request.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
String name = headers.name(i);
if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
log("\t" + name + ": " + headers.value(i));
}
}
log(" ");
if (logBody && hasRequestBody) {
if (isPlaintext(requestBody.contentType())) {
bodyToString(request);
} else {
log("\tbody: maybe [binary body], omitted!");
}
}
}
} catch (Exception e) {
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
} finally {
log("--> END " + request.method());
}
}
private Response logForResponse(Response response, long tookMs) {
Response.Builder builder = response.newBuilder();
Response clone = builder.build();
ResponseBody responseBody = clone.body();
boolean logBody = (printLevel == Level.BODY);
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
try {
log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)");
if (logHeaders) {
Headers headers = clone.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
log("\t" + headers.name(i) + ": " + headers.value(i));
}
log(" ");
if (logBody && HttpHeaders.hasBody(clone)) {
if (responseBody == null) return response;
if (isPlaintext(responseBody.contentType())) {
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // 请求整个流
Buffer buffer = source.buffer();
Charset charset = getCharset(responseBody.contentType());
String body = buffer.clone().readString(charset);
log("\tbody:" + body);
} else {
log("\tbody: maybe [binary body], omitted!");
}
}
}
} catch (Exception e) {
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
} finally {
log("<-- END HTTP");
}
return response;
}
private static Charset getCharset(MediaType contentType) {
Charset charset = contentType != null ? contentType.charset(UTF8) : UTF8;
if (charset == null) charset = UTF8;
return charset;
}
/**
* Returns true if the body in question probably contains human readable text. Uses a small sample
* of code points to detect unicode control characters commonly used in binary file signatures.
*/
private static boolean isPlaintext(MediaType mediaType) {
if (mediaType == null) return false;
if (mediaType.type() != null && mediaType.type().equals("text")) {
return true;
}
String subtype = mediaType.subtype();
if (subtype != null) {
subtype = subtype.toLowerCase();
if (subtype.contains("x-www-form-urlencoded") || subtype.contains("json") || subtype.contains("xml") || subtype.contains("html")) //
return true;
}
return false;
}
private void bodyToString(Request request) {
try {
Request copy = request.newBuilder().build();
RequestBody body = copy.body();
if (body == null) return;
Buffer buffer = new Buffer();
body.writeTo(buffer);
Charset charset = getCharset(body.contentType());
log("\tbody:" + buffer.readString(charset));
// 重置请求体以确保后续处理不受影响
buffer.clear();
} catch (Exception e) {
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,9 @@
package com.yutou.okhttp;
import okhttp3.Request;
import java.util.HashMap;
public interface IRequestParam {
Request getRequest(HashMap<String,String> header, HashMap<String,String> map, Request request);
}

View File

@@ -0,0 +1,44 @@
package com.yutou.okhttp;
import com.yutou.qqbot.utlis.ConfigTools;
import okhttp3.Request;
import java.util.HashMap;
public class ParamsContext {
private IRequestParam iRequestParam;
private Request request;
private HashMap<String, String> map;
private HashMap<String, String> headerMap;
public ParamsContext(HashMap<String, String> map, Request request) {
if (map == null) {
map = new HashMap<>();
}
this.map = map;
this.request = request;
this.headerMap = new HashMap<>();
}
public ParamsContext(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
if (map == null) {
map = new HashMap<>();
}
this.map = map;
this.request = request;
this.headerMap = headerMap;
}
public Request getInRequest() {
switch (request.method()) {
case "GET":
iRequestParam = new GetRequestParams();
break;
case "POST":
iRequestParam = new PostRequestParams();
break;
}
headerMap.put("User-Agent", ConfigTools.getUserAgent());
return iRequestParam.getRequest(headerMap, map, request);
}
}

View File

@@ -0,0 +1,74 @@
package com.yutou.okhttp;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.utlis.Log;
import okhttp3.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class PostRequestParams implements IRequestParam {
@Override
public Request getRequest(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
Headers.Builder headerBuilder = request.headers().newBuilder();
if (!headerMap.isEmpty()) {
for (String key : headerMap.keySet()) {
headerBuilder.add(key, headerMap.get(key));
}
}
if (request.body() instanceof FormBody) {
FormBody.Builder bodyBuilder = new FormBody.Builder();
FormBody formBody = (FormBody) request.body();
for (int i = 0; i < formBody.size(); i++) {
bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
}
for (String key : map.keySet()) {
bodyBuilder.addEncoded(key, String.valueOf(map.get(key)));
}
formBody = bodyBuilder.build();
request = request.newBuilder().headers(headerBuilder.build()).post(formBody).build();
} else if (request.body() != null) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), toUrlParams(map));
request = request.newBuilder()
.headers(headerBuilder.build())
.post(request.body())
.post(requestBody).build();
}
return request;
}
public static String toUrlParams(JSONObject json) {
StringBuilder string = new StringBuilder();
Set<String> keys = json.keySet();
for (String key : keys) {
try {
string.append("&").append(key).append("=").append(URLEncoder.encode(json.getString(key), "UTF-8"));
} catch (Exception e) {
Log.e(e);
try {
string.append("&").append(URLEncoder.encode(key, "UTF-8")).append("=");
// string += "&" + key + "=";
} catch (Exception e1) {
string.append("&").append(key).append("=");
}
}
}
string = new StringBuilder(string.substring(1, string.length()).replaceAll(" ", ""));
return string.toString();
}
public static String toUrlParams(Map<String, String> map) {
if (map.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder();
for (String key : map.keySet()) {
builder.append(key).append("=").append(map.get(key)).append("&");
}
return builder.substring(0, builder.length() - 1);
}
}

View File

@@ -0,0 +1,141 @@
package com.yutou.okhttp.api;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.bind.DateTypeAdapter;
import com.yutou.okhttp.HttpBody;
import com.yutou.okhttp.HttpLoggingInterceptor;
import com.yutou.okhttp.ParamsContext;
import com.yutou.okhttp.converter.JsonCallAdapter;
import com.yutou.okhttp.converter.JsonConverterFactory;
import lombok.val;
import okhttp3.*;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class BaseApi {
private String URL;
private HashMap<String, String> params = new HashMap<>();
private HashMap<String, String> headers = new HashMap<>();
public BaseApi setURL(String URL) {
this.URL = URL;
return this;
}
public BaseApi setHeaders(HashMap<String, String> headers) {
this.headers = headers;
return this;
}
public void addHeader(HashMap<String, String> headers) {
this.headers.putAll(headers);
}
public BaseApi setParams(HashMap<String, String> params) {
this.params = params;
return this;
}
public void useCookie(JSONObject json) {
StringBuilder ck = new StringBuilder();
json.remove("sql_time");
json.remove("gourl");
for (String key : json.keySet()) {
ck.append(key).append("=").append(json.getString(key)).append(";");
}
headers.put("Cookie", ck.toString());
setHeaders(headers);
}
/**
* 创建一个接口方法
*
* @param okHttpClient okhttp客户端
* @param converterFactory 处理工厂类
* @param callAdapterFactory 请求适配器工厂
* @param baseUrl 基础地质
* @param service 接口
* @param <T> 接口泛型
* @return 接口
*/
public <T> T create(OkHttpClient okHttpClient, Converter.Factory converterFactory, CallAdapter.Factory callAdapterFactory, String baseUrl, Class<T> service) {
Retrofit.Builder builder = new Retrofit.Builder()
//基础url
.baseUrl(baseUrl)
//客户端OKHttp
.client(okHttpClient);
//添加转换工厂
if (null != converterFactory) {
builder.addConverterFactory(converterFactory);
}
//添加请求工厂
if (null != callAdapterFactory) {
builder.addCallAdapterFactory(callAdapterFactory);
}
//创建retrofit对象
Retrofit retrofit = builder.build();
//返回创建的api
return retrofit.create(service);
}
public <T> T createApi(Class<T> apiClass) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.create();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor("http");
loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient()
.newBuilder()
.callTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.connectTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.addInterceptor(initQuery())
.addInterceptor(loggingInterceptor);
return create(builder.build(),
JsonConverterFactory.create(gson),
JsonCallAdapter.create(),
URL,
apiClass);
}
public Interceptor initQuery() {
Interceptor addQueryParameterInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//配置公共参数
request = new ParamsContext(headers, params, request).getInRequest();
val proceed = chain.proceed(request);
if (!proceed.isSuccessful()) {
HttpBody<?> httpBody = new HttpBody<>();
httpBody.setCode(200);
val parse = JSONObject.parse(proceed.body().string());
httpBody.setRetcode(parse.getInteger("code"));
httpBody.setMsg(parse.getString("message"));
ResponseBody errorResponseBody = ResponseBody.create(
JSONObject.toJSONString(httpBody),
MediaType.get("application/json; charset=utf-8"));
val newResponse=proceed.newBuilder()
.code(200)
.body(errorResponseBody).build();
return newResponse;
}
return proceed;
}
};
return addQueryParameterInterceptor;
}
}

View File

@@ -0,0 +1,19 @@
package com.yutou.okhttp.converter;
import org.jetbrains.annotations.Nullable;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class JsonCallAdapter extends CallAdapter.Factory{
public static JsonCallAdapter create(){
return new JsonCallAdapter();
}
@Nullable
@Override
public CallAdapter<?, ?> get(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
}

View File

@@ -0,0 +1,41 @@
package com.yutou.okhttp.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import retrofit2.Converter;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import org.jetbrains.annotations.Nullable;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class JsonConverterFactory extends Converter.Factory {
Gson gson;
public static JsonConverterFactory create(Gson gson) {
return new JsonConverterFactory(gson);
}
private JsonConverterFactory(Gson gson) {
this.gson = gson;
}
@Nullable
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
// return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonRequestBodyConverter<>(gson,adapter);
}
@Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
// return super.responseBodyConverter(type, annotations, retrofit);
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonResponseBodyConverter<>(gson,adapter,type);
}
}

View File

@@ -0,0 +1,37 @@
package com.yutou.okhttp.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonWriter;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import org.jetbrains.annotations.Nullable;
import retrofit2.Converter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
Gson gson;
TypeAdapter<T> adapter;
public JsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson=gson;
this.adapter=adapter;
}
@Nullable
@Override
public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), StandardCharsets.UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
byte[] bytes = buffer.readByteArray();
return RequestBody.create(MediaType.parse("application/json; charset=UTF-8"),bytes );
}
}

View File

@@ -0,0 +1,58 @@
package com.yutou.okhttp.converter;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.yutou.okhttp.HttpBody;
import okhttp3.ResponseBody;
import org.jetbrains.annotations.Nullable;
import retrofit2.Converter;
import java.io.IOException;
import java.lang.reflect.Type;
public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
Gson gson;
TypeAdapter<?> adapter;
Type type;
public JsonResponseBodyConverter(Gson gson, TypeAdapter<?> adapter, Type type) {
this.gson = gson;
this.adapter = adapter;
this.type = type;
}
@Nullable
@Override
public T convert(ResponseBody responseBody) throws IOException {
String string = new String(responseBody.bytes());
responseBody.close();
HttpBody<T> body;
try {
body = JSONObject.parseObject(string, type);
if(body.getData()==null){
JSONObject jt=JSONObject.parseObject(JSONObject.toJSONString(new HttpBody<>()));
jt.put("data",JSONObject.parseObject(string));
HttpBody<T> bt=JSONObject.parseObject(jt.toJSONString(),type);
body.setData(bt.getData());
}
body.setSrc(string);
return (T) body;
} catch (Exception e) {
e.printStackTrace();
try {
body = new HttpBody<>();
body.setData(JSONObject.parseObject(string, type));
body.setSrc(string);
} catch (Exception e2) {
e2.printStackTrace();
body = new HttpBody<>();
body.setSrc(string);
}
}
return (T) body;
}
}

View File

@@ -0,0 +1,87 @@
package com.yutou.qqbot.Controllers;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.utlis.BangumiTools;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
@RestController
@RequestMapping("/bgm")
public class AnimeController {
@GetMapping("/today")
public Map<String, Object> getTodayAnim() {
Map<String, Object> returnData = new HashMap<>();
// 获取全部一周的数据
JSONObject allData = BangumiTools.getBangumi(-1);
if (allData == null) {
return returnData;
}
JSONArray bangumiArray = allData.getJSONArray("bangumi");
if (bangumiArray == null || bangumiArray.isEmpty()) {
return returnData;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.setTime(new Date());
int todayId = calendar.get(Calendar.DAY_OF_WEEK) - 1;
if (todayId == 0) {
todayId = 7; // 处理星期日的情况
}
int tomorrowId = todayId % 7 + 1; // 计算明天对应的 weekday id
JSONObject todayData = null;
JSONObject tomorrowData = null;
for (Object obj : bangumiArray) {
JSONObject item = (JSONObject) obj;
int weekdayId = item.getJSONObject("weekday").getInteger("id");
if (weekdayId == todayId) {
todayData = item;
}
if (weekdayId == tomorrowId) {
tomorrowData = item;
}
}
// 打印当日数据
if (todayData != null) {
JSONArray items = todayData.getJSONArray("items");
if (items != null && !items.isEmpty()) {
for (Object o : items) {
JSONObject itemObj = (JSONObject) o;
if (itemObj.getString("name_cn") == null || itemObj.getString("name_cn").isEmpty()) {
itemObj.put("name_cn", itemObj.getString("name"));
}
}
}
returnData.put("today",todayData);
}
// 打印明日数据
if (tomorrowData != null) {
JSONArray items = tomorrowData.getJSONArray("items");
if (items != null && !items.isEmpty()) {
for (Object o : items) {
JSONObject itemObj = (JSONObject) o;
if (itemObj.getString("name_cn") == null || itemObj.getString("name_cn").isEmpty()) {
itemObj.put("name_cn", itemObj.getString("name"));
}
}
}
returnData.put("nextDay",tomorrowData);
}
return returnData;
}
}

View File

@@ -0,0 +1,122 @@
package com.yutou.qqbot.Controllers;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.QQDatabase;
import com.yutou.napcat.handle.At;
import com.yutou.napcat.handle.BaseHandle;
import com.yutou.napcat.handle.Image;
import com.yutou.napcat.handle.Text;
import com.yutou.napcat.model.SendMessageResponse;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.utlis.AppTools;
import com.yutou.qqbot.utlis.HttpTools;
import com.yutou.qqbot.utlis.RedisTools;
import com.yutou.qqbot.utlis.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Controller
public class AppController {
@RequestMapping("/restart.do")
@ResponseBody
public String restart() {
AppTools.exec("cd /home/yutou/public/servier/qqbot && ./start.sh", null, true, false);
return "";
}
@ResponseBody
@RequestMapping("/door/set.do")
public String openDoor(String status) {
RedisTools.set("door", status);
return "1";
}
@ResponseBody
@RequestMapping("/door/get.do")
public String getDoor() {
if ("open".equals(RedisTools.get("door"))) {
RedisTools.set("door", "on");
return "1";
}
return "0";
}
@ResponseBody
@RequestMapping("/door/status.do")
public String getStatus() {
String status = RedisTools.get("door");
if ("open".equals(status)) {
return "0";
} else if ("on".equals(status)) {
return "2";
} else if ("over".equals(status)) {
RedisTools.set("door", "ready");
return "1";
}
return "-1";
}
@ResponseBody
@RequestMapping("/qq/send.do")
public String sendQQ(@RequestBody JSONObject json) {
File image = null;
if (json.getString("message").isEmpty()) {
return "not message";
}
List<BaseHandle<?>> list=new ArrayList<>();
list.add(new Text(json.getString("message")));
if(json.getString("image")!=null&&!json.getString("image").isEmpty()){
list.add(new Image(json.getString("image")));
}
SendMessageResponse sent = QQBotManager.getInstance().sendMessage(QQDatabase.checkFriend(json.getLong("qq")),
json.getLong("qq"),
list
);
return sent == null ? "0" : sent.getId() + "";
}
@ResponseBody
@RequestMapping("/qq/file.do")
public String sendFile(@RequestParam("image") MultipartFile file) throws Exception {
String path = AppTools.createFile("tmp", file, System.currentTimeMillis() + ".png");
if (StringUtils.isEmpty(path)) {
return "not file";
}
File _file = new File(path);
QQBotManager.getInstance().sendMessage(_file, 583819556L, "time = " + AppTools.getToDayNowTimeToString());
return "ok";
}
@RequestMapping("/test.do")
@ResponseBody
public String test(HttpServletResponse response) {
System.out.println("NAS自动关机");
/* try {
response.sendRedirect("http://192.168.31.88:9999/live/index.m3u8");
} catch (IOException e) {
e.printStackTrace();
}*/
// return HttpTools.http_get("http://192.168.31.88:9999/live/index.m3u8",null);
return "1";
}
@RequestMapping("*.ts")
public void test2(HttpServletResponse response, HttpServletRequest request) {
try {
response.sendRedirect("http://192.168.31.88:9999/live" + request.getRequestURI());
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,30 @@
package com.yutou.qqbot.Controllers;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.models.BiliBili.BiliVideo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BiliBiliController {
@RequestMapping("/bilibili/down.do")
@ResponseBody
public JSONObject downloadBili(String data) {
new Thread(() -> {
JSONObject json = JSONObject.parseObject(data);
System.out.println("json = " + json);
String url = json.getString("url");
boolean downDanmu = json.containsKey("danmu") && "on".equals(json.getString("danmu"));
boolean merge = json.containsKey("merge") && "on".equals(json.getString("merge"));
BiliVideo video = new BiliVideo(QQBotManager.defQQ);
video.downVideo(url, downDanmu, merge);
}
).start();
JSONObject json = new JSONObject();
json.put("msg", "ok");
json.put("code", 0);
return json;
}
}

View File

@@ -0,0 +1,240 @@
package com.yutou.qqbot.Controllers;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.data.jianr.AndroidDevice;
import com.yutou.qqbot.data.jianr.JianRScriptV2Data;
import com.yutou.qqbot.utlis.JianRTaskManager;
import com.yutou.qqbot.utlis.RedisTools;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
@Controller
public class JianRScriptController {
@RequestMapping("/jianr/run.do")
@ResponseBody
public JSONObject runScript(String task, String device, String modelName) {
JSONObject json = new JSONObject();
String data = RedisTools.getHashMap(JianRTaskManager.Redis_Script, task);
String deviceJsonString = RedisTools.getHashMap(JianRTaskManager.Redis_Device, device);
if (data == null || deviceJsonString == null) {
json.put("code", -1);
json.put("msg", "没有找到该方案或设备错误,请配置");
} else {
JianRScriptV2Data script = JSON.parseObject(data, JianRScriptV2Data.class);
AndroidDevice androidDevice = JSON.parseObject(deviceJsonString, AndroidDevice.class);
JianRTaskManager manager = JianRTaskManager.getInstance();
if (manager.isRunning()) {
manager.stop();
}
for (int i = 0; i < androidDevice.getDeviceDisplay().size(); i++) {
if (androidDevice.getDeviceDisplay().get(i).getTitle().equals(modelName)) {
manager.setModelId(i);
break;
}
}
manager.setTask(script, androidDevice);
manager.start();
json.put("code", 0);
json.put("msg", "任务创建成功");
}
return json;
}
@RequestMapping("/jianr/stop.do")
@ResponseBody
public JSONObject stop() {
JianRTaskManager.getInstance().stop();
JSONObject json = new JSONObject();
json.put("code", 0);
json.put("msg", "任务已停止");
return json;
}
@RequestMapping("/jianr/status.do")
@ResponseBody
public JSONObject status() {
JSONObject json = new JSONObject();
JSONObject data = new JSONObject();
JianRTaskManager manager = JianRTaskManager.getInstance();
data.put("status", manager.isRunning());
data.put("runIndex", manager.getRunIndex());
data.put("taskName", manager.getTaskName());
data.put("log", manager.getLog());
json.put("code", 0);
json.put("data", data);
return json;
}
@RequestMapping("/jianr/task/list.do")
@ResponseBody
public JSONObject tasks() {
JSONObject json = new JSONObject();
JSONArray array = new JSONArray();
Map<String, String> map = RedisTools.getHashMap(JianRTaskManager.Redis_Script);
array.addAll(map.keySet());
json.put("code", 0);
json.put("data", array);
return json;
}
@RequestMapping("/jianr/task/add.do")
@ResponseBody
public JSONObject addTask(String task) {
JSONObject json = new JSONObject();
JSONObject data = JSON.parseObject(task);
if (data == null) {
json.put("code", -1);
json.put("msg", "JSON格式错误");
} else {
String taskName = data.getString("title");
if (RedisTools.getHashMap(JianRTaskManager.Redis_Script).containsKey(taskName)) {
json.put("code", -1);
json.put("msg", "该任务名称已存在");
} else {
RedisTools.setHashMap(JianRTaskManager.Redis_Script, taskName, task);
json.put("code", 0);
json.put("msg", "任务创建成功");
}
}
return json;
}
@RequestMapping("/jianr/task/get.do")
@ResponseBody
public JSONObject getTask(String task) {
JSONObject json = new JSONObject();
json.put("code", 0);
json.put("data", RedisTools.getHashMap(JianRTaskManager.Redis_Script, task));
return json;
}
@RequestMapping("/jianr/task/remove.do")
@ResponseBody
public JSONObject removeTask(String task) {
RedisTools.removeHashMap(JianRTaskManager.Redis_Script, task);
JSONObject json = new JSONObject();
json.put("code", 0);
json.put("msg", "任务删除成功");
return json;
}
@RequestMapping("/jianr/device/connect.do")
@ResponseBody
public JSONObject connectDevice(String device) {
JSONObject json = new JSONObject();
JianRTaskManager.getInstance().connect(device);
json.put("code", 0);
json.put("msg", "成功");
return json;
}
@RequestMapping("/jianr/device/add.do")
@ResponseBody
public JSONObject addDevice(String device) {
Map<String, String> hashMap = RedisTools.getHashMap(JianRTaskManager.Redis_Device);
JSONObject deviceJson = JSON.parseObject(device);
JSONObject json = new JSONObject();
json.put("code", 0);
if (deviceJson == null) {
json.put("msg", "JSON格式错误");
} else {
if (hashMap.containsKey(device)) {
json.put("msg", "设备已存在");
} else {
json.put("msg", RedisTools.setHashMap(JianRTaskManager.Redis_Device,
deviceJson.getString("title"), device) ?
"设备添加成功" : "设备添加失败");
}
}
return json;
}
@RequestMapping("/jianr/device/edit.do")
@ResponseBody
public JSONObject editDevice(String device, String oldDevice) {
JSONObject deviceJson = JSON.parseObject(device);
JSONObject json = new JSONObject();
json.put("code", 0);
if (deviceJson == null) {
json.put("msg", "JSON格式错误");
} else {
RedisTools.removeHashMap(JianRTaskManager.Redis_Device, oldDevice);
json.put("msg", RedisTools.setHashMap(JianRTaskManager.Redis_Device,
deviceJson.getString("title"), device) ?
"设备修改成功" : "设备修改失败");
}
return json;
}
@RequestMapping("/jianr/device/del.do")
@ResponseBody
public JSONObject delDevice(String device) {
JSONObject deviceJson = JSON.parseObject(device);
JSONObject json = new JSONObject();
json.put("code", 0);
if (deviceJson == null) {
json.put("msg", "JSON格式错误");
} else {
json.put("msg", RedisTools.removeHashMap(JianRTaskManager.Redis_Device) ?
"设备修改成功" : "设备修改失败");
}
return json;
}
@RequestMapping("/jianr/device/list.do")
@ResponseBody
public JSONObject getDeviceList() {
Map<String, String> hashMap = RedisTools.getHashMap(JianRTaskManager.Redis_Device);
JSONObject json = new JSONObject();
JSONArray array = new JSONArray();
json.put("code", 0);
hashMap.keySet().forEach(key -> {
JSONObject device = JSONObject.parseObject(hashMap.get(key));
JSONArray child = new JSONArray();
JSONObject item = new JSONObject();
JSONObject del = new JSONObject();
JSONObject edit = new JSONObject();
JSONObject select = new JSONObject();
JSONObject connect = new JSONObject();
item.put("title", key);
del.put("title", "删除");
del.put("data", "del");
del.put("device", device);
edit.put("title", "编辑");
edit.put("data", "edit");
edit.put("device", device);
select.put("title", "选择");
select.put("data", "select");
select.put("device", device);
connect.put("title", "连接设备");
connect.put("data", "connect");
connect.put("device", device);
child.add(connect);
child.add(select);
child.add(del);
child.add(edit);
item.put("child", child);
array.add(item);
});
json.put("data", array);
return json;
}
public static void main(String[] args) {
Map<String, String> hashMap = RedisTools.getHashMap(JianRTaskManager.Redis_Device);
JSONObject json = new JSONObject();
JSONArray array = new JSONArray();
json.put("code", 0);
hashMap.keySet().forEach(key -> {
JSONObject item = JSONObject.parseObject(hashMap.get(key));
array.add(item);
});
json.put("data", array);
System.out.println(json);
}
}

View File

@@ -0,0 +1,79 @@
package com.yutou.qqbot.Controllers;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.models.XiaoMi.MiRouter;
import com.yutou.qqbot.utlis.HttpTools;
import com.yutou.qqbot.utlis.RedisTools;
import com.yutou.qqbot.utlis.XiaoMiRouter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/router/")
public class MiRouterDevices {
@RequestMapping("device/add.do")
@ResponseBody
public String addDevice(HttpServletRequest request,String qq) {
String data = RedisTools.get(MiRouter.redis_key);
JSONArray array;
if (data == null) {
array = new JSONArray();
} else {
array = JSON.parseArray(data);
}
for (Object o : array) {
JSONObject item = (JSONObject) o;
if (item.getString("mac").equals(getRemoteAddress(request.getRemoteAddr()))) {
return "已经添加过了";
}
}
JSONObject item=new JSONObject();
item.put("qq",qq);
item.put("mac",getRemoteAddress(request.getRemoteAddr()));
item.put("online",false);
array.add(item);
RedisTools.set(MiRouter.redis_key,array.toString());
return "添加成功,关闭当前页面即可";
}
@ResponseBody
@RequestMapping("device/del.do")
public String delDevice(HttpServletRequest request,String qq){
String data = RedisTools.get(MiRouter.redis_key);
JSONArray array;
if (data == null) {
array = new JSONArray();
} else {
array = JSON.parseArray(data);
}
JSONArray _array= JSON.parseArray(array.toString());
for (Object o : array) {
JSONObject item = (JSONObject) o;
if (item.getString("mac").equals(getRemoteAddress(request.getRemoteAddr()))) {
_array.remove(item);
RedisTools.set(MiRouter.redis_key,_array.toString());
return "已成功删除";
}
}
return "未找到该设备";
}
private String getRemoteAddress(String ip) {
JSONObject data = JSON.parseObject(HttpTools.get(XiaoMiRouter.getInstance().getDeviceListUrl()));
if (data.getInteger("code") == 0) {
JSONArray array=data.getJSONArray("list");
for (Object o : array) {
JSONObject item= (JSONObject) o;
if(item.getJSONArray("ip").getJSONObject(0).getString("ip").equals(ip)){
return item.getString("mac");
}
}
}
return null;
}
}

View File

@@ -3,27 +3,20 @@ package com.yutou.qqbot.Listeners;
import com.yutou.qqbot.MessageEvent.AdminMessage;
import com.yutou.qqbot.QQNumberManager;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.utlis.Log;
import kotlin.coroutines.CoroutineContext;
import net.mamoe.mirai.event.EventHandler;
import net.mamoe.mirai.event.ListeningStatus;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.event.events.GroupMessageEvent;
import net.mamoe.mirai.event.events.MessageEvent;
import org.jetbrains.annotations.NotNull;
public class QQMessageListener extends SimpleListenerHost {
public class QQMessageListener {
@Override
public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception) {
// super.handleException(context, exception);
exception.printStackTrace();
}
@EventHandler
public ListeningStatus onMessage(MessageEvent event) {
long qqNumber;
public void onMessage() {
/* long qqNumber;
boolean isGroup;
if (event instanceof GroupMessageEvent) {
qqNumber = ((GroupMessageEvent) event).getGroup().getId();
@@ -42,7 +35,6 @@ public class QQMessageListener extends SimpleListenerHost {
Model useModel = (Model) model.getDeclaredConstructor().newInstance();
if (!useModel.isUserPublic()) {
if (!QQNumberManager.getManager().isExistsPower(event.getSource().getFromId(), useModel.getUsePowers())) {
Log.i("用户没有权限",event.getSource().getFromId()+" > "+model.getSimpleName());
continue;
}
}
@@ -53,7 +45,7 @@ public class QQMessageListener extends SimpleListenerHost {
}
}
return ListeningStatus.LISTENING; // 表示继续监听事件
return ListeningStatus.LISTENING; // 表示继续监听事件*/
}

View File

@@ -3,9 +3,16 @@ package com.yutou.qqbot.MessageEvent;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.QQNumberManager;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.models.WebSign.BaiHeHui;
import com.yutou.qqbot.models.WebSign.NicePT;
import com.yutou.qqbot.models.WebSign.Tsdm;
import com.yutou.qqbot.models.WebSign.ZhuZhu;
import com.yutou.qqbot.utlis.AppTools;
import com.yutou.qqbot.utlis.Log;
import com.yutou.qqbot.utlis.StringUtils;
import com.yutou.qqbot.utlis.WebClient;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class AdminMessage extends Message {
@@ -21,9 +28,13 @@ public class AdminMessage extends Message {
public static final String SYSTEM_RESTART_QQ = "!重启qq";
public static final String SYSTEM_RESTART_TOOLS = "!重启服务";
public static final String SYSTEM_UPDATE_QQ = "!更新qq";
public static final String SYSTEM_UPDATE_NAS = "!更新服务";
private static final String SHOW = "!列表";
private static final String HELP = "!help";
private static final String SIGN = "!签到";
}
public AdminMessage(Long qq, String msg) {
@@ -74,6 +85,12 @@ public class AdminMessage extends Message {
if (msgGroup.length == 1) {
StringBuilder builder = new StringBuilder();
for (Class<?> aClass : Model.classList) {
try {
Model model = (Model) aClass.getDeclaredConstructor().newInstance();
builder.append("[").append(model.getModelName()).append("]");
} catch (Exception e) {
e.printStackTrace();
}
builder.append(aClass.getName()).append("\n");
}
QQBotManager.getInstance().sendMessage(qq, "使用方法:" + QQCommands.MODEL_ADD + " [qqnumber] 模块" + "\n" + "可设置以下模块,用&分割");
@@ -81,31 +98,43 @@ public class AdminMessage extends Message {
} else {
if (msgGroup.length <= 2) {
addModel(msgGroup[1], null);
} else {
if ("this".equals(msgGroup[1])) {
addModel(sendQQ + "", msgGroup[2]);
} else {
addModel(msgGroup[1], msgGroup[2]);
}
}
}
}
case QQCommands.MODEL_SHOW -> {
if (msgGroup.length == 1) {
QQBotManager.getInstance().sendMessage(qq, "使用方法:" + QQCommands.MODEL_SHOW + " [qqnumber]");
} else {
List<String> list = QQNumberManager.getManager().getUseModel(Long.parseLong(msgGroup[1]));
String qqGroup = msgGroup[1];
if ("this".equals(qqGroup)) {
qqGroup = sendQQ + "";
}
List<String> list = QQNumberManager.getManager().getUseModel(Long.parseLong(qqGroup));
StringBuilder builder = new StringBuilder();
for (String power : list) {
builder.append(power).append("\n");
}
QQBotManager.getInstance().sendMessage(qq, Long.parseLong(msgGroup[1]) + " 拥有以下模块:" + builder);
QQBotManager.getInstance().sendMessage(qq, Long.parseLong(qqGroup) + " 拥有以下模块:" + builder);
}
}
case QQCommands.MODEL_DEL -> {
if (msgGroup.length == 1) {
QQBotManager.getInstance().sendMessage(qq, "使用方法:" + QQCommands.MODEL_DEL + " [qqnumber] 模块 用&分割");
} else {
String qqGroup = msgGroup[1];
if ("this".equals(qqGroup)) {
qqGroup = sendQQ + "";
}
if (msgGroup.length <= 2) {
delModel(msgGroup[1], null);
delModel(qqGroup, null);
} else {
delModel(msgGroup[1], msgGroup[2]);
delModel(qqGroup, msgGroup[2]);
}
}
}
@@ -138,6 +167,77 @@ public class AdminMessage extends Message {
System.out.println("结束进程");
AppTools.exec("cd /home/yutou/public/servier/tools && ./start.sh", null, true, false);
}
case QQCommands.SYSTEM_UPDATE_QQ -> {
QQBotManager.getInstance().sendMessage(qq, "正在更新qq");
System.out.println("结束进程");
AppTools.exec("cd /home/yutou/git/QQBot && ./update.sh", null, true, false);
}
case QQCommands.SYSTEM_UPDATE_NAS -> {
QQBotManager.getInstance().sendMessage(qq, "正在更新NAS服务");
System.out.println("结束进程");
AppTools.exec("cd /home/yutou/git/nas-service && ./update.sh", null, true, false);
}
case QQCommands.SIGN -> {
boolean sign = true;
boolean tsdmSign = false, baiheSign = false, nicePtSign = false, zhuzhuSign=false;
Log.i("开始签到");
try {
if (new Tsdm().tsdmSign()) {
tsdmSign = true;
}
} catch (Exception e) {
sign = false;
QQBotManager.getInstance().sendMessage(qq, "tsdm签到失败:" + AppTools.getExceptionString(e));
e.printStackTrace();
}
try {
if (new BaiHeHui().sign()) {
baiheSign = true;
}
} catch (Exception e) {
sign = false;
QQBotManager.getInstance().sendMessage(qq, "百合会签到失败:" + AppTools.getExceptionString(e));
e.printStackTrace();
}
try {
if (new NicePT().sign()) {
nicePtSign = true;
}
} catch (Exception e) {
sign = false;
QQBotManager.getInstance().sendMessage(qq, "NicePT签到失败:" + AppTools.getExceptionString(e));
e.printStackTrace();
}
try {
if (new ZhuZhu().sign()) {
zhuzhuSign = true;
}
} catch (Exception e) {
sign = false;
QQBotManager.getInstance().sendMessage(qq, "HiRes花园签到失败:" + AppTools.getExceptionString(e));
e.printStackTrace();
}
if (sign && tsdmSign && baiheSign && nicePtSign) {
QQBotManager.getInstance().sendMessage(qq, "签到任务完成");
}else{
StringBuilder builder=new StringBuilder();
if(!tsdmSign){
builder.append("天使动漫签到失败\n");
}
if(!baiheSign){
builder.append("百合会签到失败\n");
}
if(!nicePtSign){
builder.append("NicePT签到失败\n");
}
if(!zhuzhuSign){
builder.append("HiRes花园签到失败\n");
}
QQBotManager.getInstance().sendMessage(qq,builder.toString());
}
WebClient.getInstance().quit();
}
}
}
@@ -193,20 +293,22 @@ public class AdminMessage extends Message {
}
private void delModel(String qq, String model) {
boolean flag = false;
try {
if (model == null) {
List<String> list = QQNumberManager.getManager().getUseModel(Long.parseLong(qq));
for (String power : list) {
QQNumberManager.getManager().delUseModel(Long.parseLong(qq), Class.forName(power));
flag = QQNumberManager.getManager().delUseModel(Long.parseLong(qq), Class.forName(power));
}
} else {
for (String power : model.split("&")) {
QQNumberManager.getManager().delUseModel(Long.parseLong(qq), Class.forName(power));
flag = QQNumberManager.getManager().delUseModel(Long.parseLong(qq), Class.forName(power));
}
}
} catch (Exception e) {
e.printStackTrace();
}
QQBotManager.getInstance().sendMessage(sendQQ, flag ? "删除成功" : "删除失败");
}
}

View File

@@ -1,16 +1,24 @@
package com.yutou.qqbot;
import com.yutou.napcat.http.NapCatApi;
import com.yutou.okhttp.HttpLoggingInterceptor;
import com.yutou.qqbot.utlis.ConfigTools;
import com.yutou.qqbot.utlis.RedisTools;
import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class QQBotApplication {
public static final String version="QQBot v.1.0.1";
public static final String version = "QQBot v.1.7.24";
public static void main(String[] args) {
System.out.println("version = " + version);
SpringApplication.run(QQBotApplication.class, args);
RedisTools.initRedisPoolSub();
QQBotManager.getInstance();
val log = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.QQ_LOG, Boolean.class,true);
NapCatApi.setLog(log);
}
}

View File

@@ -1,13 +1,27 @@
package com.yutou.qqbot;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.enums.MessageEnum;
import com.yutou.napcat.event.MessageEvent;
import com.yutou.napcat.handle.BaseHandle;
import com.yutou.napcat.handle.OtherHandle;
import com.yutou.qqbot.MessageEvent.AdminMessage;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.utlis.AppTools;
import com.yutou.qqbot.utlis.RedisTools;
import com.yutou.qqbot.utlis.XiaoMiRouter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Set;
@Controller
public class QQBotController {
@@ -33,4 +47,58 @@ public class QQBotController {
AppTools.sendServer(title, msg);
return "ok";
}
@ResponseBody
@RequestMapping("/napcat/qq/bot.do")
public String qq_bot(HttpServletRequest request, HttpServletResponse response) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
BufferedInputStream stream = new BufferedInputStream(request.getInputStream());
byte[] bytes = new byte[1024];
int len = 0, size;
while ((len = stream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
outputStream.flush();
}
String str = outputStream.toString(StandardCharsets.UTF_8);
MessageEvent event = MessageEvent.parseHandle(str);
long qqNumber = event.isGroup() ? event.getGroupId() : event.getUserId();
boolean isGroup = event.isGroup();
if ((event.isGroup() && event.getSource().getUserId() == 583819556L) || (!event.isGroup() && event.getUserId() == 583819556L)) {
new AdminMessage(qqNumber, event.getRawMessage());
}
for (Class<?> model : Model.classList) {
if (QQNumberManager.getManager().isUseModel(qqNumber, model) || !isGroup) {
try {
Model useModel = (Model) model.getDeclaredConstructor().newInstance();
if (!useModel.isUserPublic()) {
if (!QQNumberManager.getManager().isExistsPower(event.getSource().getFromId(), useModel.getUsePowers())) {
continue;
}
}
useModel.onMessage(qqNumber, event, isGroup);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "200";
}
@ResponseBody
@RequestMapping("/router/wan1ip.do")
public String getWan1IP(){
return XiaoMiRouter.getInstance().getWan1IPAddress();
}
@ResponseBody
@RequestMapping("/router/wan2ip.do")
public String getWan2IP(){
return XiaoMiRouter.getInstance().getWan2IPAddress();
}
}

View File

@@ -1,50 +1,36 @@
package com.yutou.qqbot;
import com.yutou.qqbot.Listeners.QQMessageListener;
import com.yutou.qqbot.models.Animal.TurnipProphet;
import com.yutou.qqbot.models.Commands.BaiduDown;
import com.yutou.qqbot.models.Commands.Bangumi;
import com.yutou.qqbot.models.Commands.System.*;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.models.WebSign.Tsdm;
import com.yutou.qqbot.models.setu.QQSetu;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.QQDatabase;
import com.yutou.napcat.handle.*;
import com.yutou.napcat.http.NapCatApi;
import com.yutou.napcat.model.FriendBean;
import com.yutou.napcat.model.GroupBean;
import com.yutou.napcat.model.GroupUserBean;
import com.yutou.napcat.model.SendMessageResponse;
import com.yutou.okhttp.BaseBean;
import com.yutou.okhttp.HttpBody;
import com.yutou.okhttp.HttpCallback;
import com.yutou.qqbot.data.MessageChainBuilder;
import com.yutou.qqbot.interfaces.ObjectInterface;
import com.yutou.qqbot.utlis.*;
import net.mamoe.mirai.Bot;
import net.mamoe.mirai.BotFactory;
import net.mamoe.mirai.event.GlobalEventChannel;
import net.mamoe.mirai.message.data.Image;
import net.mamoe.mirai.message.data.MessageChainBuilder;
import net.mamoe.mirai.utils.BotConfiguration;
import net.mamoe.mirai.utils.ExternalResource;
import okhttp3.Headers;
import retrofit2.Response;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public class QQBotManager {
public static Long defGroup = 891655174L;
public static Long defQQ = 583819556L;
static {
Model.classList.add(QQSetu.class);
Model.classList.add(Audio.class);
Model.classList.add(BtFlash.class);
Model.classList.add(Cmd.class);
Model.classList.add(Help.class);
Model.classList.add(IP.class);
Model.classList.add(OpenPC.class);
Model.classList.add(Restart.class);
Model.classList.add(ToolsIdea.class);
Model.classList.add(UpdateIP.class);
Model.classList.add(Version.class);
Model.classList.add(Bangumi.class);
Model.classList.add(TurnipProphet.class);
Model.classList.add(Tsdm.class);
Model.classList.add(BaiduDown.class);
}
private static QQBotManager botManager = null;
private Bot bot;
private static final long qqGroup = 891655174L;
private boolean isLogin = false;
private static boolean isInit = false;
@@ -54,169 +40,239 @@ public class QQBotManager {
Object isRun = ConfigTools.load(ConfigTools.CONFIG, "qq_bot");
if (isRun != null && (boolean) isRun) {
isLogin = true;
isInit = true;
init();
}
}
private void init() {
new Thread(new Runnable() {
sendMessage(true, 583819556L, "姬妻酱上线拉~☆Daze~ 当前版本:" + QQBotApplication.version);
NapCatApi.getGroupApi().getGroupList().enqueue(new HttpCallback<List<GroupBean>>() {
@Override
public void run() {
long qq = ConfigTools.load(ConfigTools.CONFIG,"qq_number",Long.class);
String password = ConfigTools.load(ConfigTools.CONFIG,"qq_password",String.class);
bot = BotFactory.INSTANCE.newBot(qq, password, new BotConfiguration() {
{
setProtocol(MiraiProtocol.ANDROID_PAD);
fileBasedDeviceInfo("qq_bot_devices_info.json");
if ("nas".equals(ConfigTools.load(ConfigTools.CONFIG, "model"))) {
noBotLog();
noNetworkLog();
public void onResponse(Headers headers, int code, String status, List<GroupBean> response, String rawResponse) {
for (GroupBean groupBean : response) {
QQDatabase.addGroup(groupBean.getGroupId(), groupBean);
QQNumberManager.getManager().addNumber(groupBean.getGroupId(), true);
}
}
@Override
public void onFailure(Throwable throwable) {
}
});
//Events.registerEvents(bot, new MessageListener());
GlobalEventChannel.INSTANCE.registerListenerHost(new QQMessageListener());
// GlobalEventChannel.INSTANCE.subscribeAlways(GroupMessageEvent.class, new MessageListener());
bot.login();
new Thread(new Runnable() {
NapCatApi.getFriendApi().getFriendList().enqueue(new HttpCallback<List<FriendBean>>() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
public void onResponse(Headers headers, int code, String status, List<FriendBean> response, String rawResponse) {
for (FriendBean friendBean : response) {
QQDatabase.addUser(friendBean.getUserId(), friendBean);
QQNumberManager.getManager().addNumber(friendBean.getUserId(), false);
}
String str = sendMessage("姬妻酱上线拉~☆Daze~ 当前版本:"+QQBotApplication.version);
Log.i(str);
}
}).start();
bot.join();
}
}).start();
}
public static QQBotManager getInstance() {
@Override
public void onFailure(Throwable throwable) {
}
});
NapCatApi.getUtilsApi().getLoginInfo().enqueue(new HttpCallback<FriendBean>() {
@Override
public void onResponse(Headers headers,int code, String status, FriendBean response, String rawResponse) {
QQDatabase.setMe(response);
}
@Override
public void onFailure(Throwable throwable) {
}
});
isInit = true;
}
public synchronized static QQBotManager getInstance() {
if (botManager == null && !isInit) {
botManager = new QQBotManager();
}
return botManager;
}
public boolean isLogin() {
return isLogin;
}
private Image getImage(File file,Long qq) {
if (bot != null) {
if(QQNumberManager.getManager().isGroup(qq)) {
return Objects.requireNonNull(bot.getGroup(qq)).uploadImage(ExternalResource.create(file));
}else{
return Objects.requireNonNull(bot.getFriend(qq)).uploadImage(ExternalResource.create(file));
}
}
return null;
}
private String getNotLoginQQ() {
return "没有登录QQ";
}
public SendMessageResponse sendPrivateMessage(Long qq, BaseHandle<?>... items) {
return sendMessage(true, qq, items);
}
private SendMessageResponse sendGroupMessage(Long group, BaseHandle<?>... items) {
return sendMessage(false, group, items);
}
public SendMessageResponse sendMessage(boolean user, Long qq, String msg) {
return sendMessage(user, qq, new Text(msg));
}
public SendMessageResponse sendMessage(Long qq, BaseHandle<?>... items) {
return sendMessage(QQDatabase.checkFriend(qq), qq, Arrays.asList(items));
}
public SendMessageResponse sendMessage(boolean isUser, Long qq, BaseHandle<?>... items) {
return sendMessage(isUser, qq, Arrays.asList(items));
}
public SendMessageResponse sendMessage(boolean isUser, Long qq, List<BaseHandle<?>> items) {
try {
if (!ConfigTools.load(ConfigTools.CONFIG, ConfigTools.QQ, Boolean.class)) {
return null;
}
MessageHandleBuild handleBuild = MessageHandleBuild
.create()
.setGroup(!isUser)
.setQQNumber(qq);
for (BaseHandle<?> item : items) {
if (item.getData() == null) {
continue;
}
if (item instanceof Reply) {
if (((Reply) item).getData().getId() == -1) {
continue;
}
}
handleBuild.add(item);
}
Response<HttpBody<SendMessageResponse>> response;
if (isUser) {
response = NapCatApi.getMessageApi().sendPrivateMsg(
handleBuild.build()
).execute();
} else {
response = NapCatApi.getMessageApi().sendGroupMsg(
handleBuild.build()
).execute();
}
if (response.body() != null) {
return response.body().getData();
}
} catch (Exception e) {
e.printStackTrace();
SendMessageResponse response = new SendMessageResponse();
response.setId(-1);
response.setE(e.getMessage());
return response;
}
return null;
}
public String sendMessage(String text) {
if (bot != null&&!StringUtils.isEmpty(text)) {
try {
return Objects.requireNonNull(bot.getGroup(qqGroup)).sendMessage(text).toString();
} catch (Exception e) {
e.printStackTrace();
}
}
return getNotLoginQQ();
return sendMessage(false,defGroup,text).toString();
}
public String sendMessage(Long group, String text) {
if (bot != null) {
try {
if(QQNumberManager.getManager().isGroup(group)) {
return Objects.requireNonNull(bot.getGroup(group)).sendMessage(text).toString();
}else{
return Objects.requireNonNull(bot.getFriend(group)).sendMessage(text).toString();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return getNotLoginQQ();
public SendMessageResponse sendMessage(Long group, String text) {
return sendMessage(QQDatabase.checkFriend(group), group, new Text(text));
}
public void sendMessage(Long group, MessageChainBuilder builder) {
if (bot != null) {
if (QQNumberManager.getManager().isGroup(group)) {
Objects.requireNonNull(bot.getGroup(group)).sendMessage(builder.asMessageChain());
System.out.println("发群");
} else {
Objects.requireNonNull(bot.getFriend(group)).sendMessage(builder.asMessageChain());
}
System.out.println("发个人");
}
}
public String sendMessage(File imageFile,Long qq,String text){
try {
if (bot != null) {
Image image = getImage(imageFile,qq);
MessageChainBuilder builder = new MessageChainBuilder();
if (image != null) {
builder.append(image);
}
builder.append(text);
if(QQNumberManager.getManager().isGroup(qq)) {
return Objects.requireNonNull(bot.getGroup(qq)).sendMessage(builder.asMessageChain()).toString();
}else{
return Objects.requireNonNull(bot.getFriend(qq)).sendMessage(builder.asMessageChain()).toString();
}
}
} catch (Exception e) {
e.printStackTrace();
public void sendMessage(File imageFile, Long qq, String text) {
sendMessage(imageFile, qq, null, text);
}
return getNotLoginQQ();
}
public String sendMessage(File imageFile, String text) {
return sendMessage(imageFile,qqGroup,text);
public void sendMessage(File imageFile, Long qq, String replyMessageId, String text) {
List<BaseHandle<?>> items = new ArrayList<>();
if (imageFile != null) {
items.add(new Image(imageFile));
}
public String sendMessage(List<File> imgs,Long qq, String text) {
if (bot != null) {
MessageChainBuilder builder = new MessageChainBuilder();
for (File img : imgs) {
builder.append(Objects.requireNonNull(getImage(img,qq)));
}
builder.append(text);
if(QQNumberManager.getManager().isGroup(qq)) {
return Objects.requireNonNull(bot.getGroup(qq)).sendMessage(builder.asMessageChain()).toString();
}else{
return Objects.requireNonNull(bot.getFriend(qq)).sendMessage(builder.asMessageChain()).toString();
}
}
return getNotLoginQQ();
if (replyMessageId != null && !replyMessageId.isEmpty()) {
items.add(new Reply(Long.parseLong(replyMessageId)));
}
if (text != null && !text.isEmpty()) {
items.add(new Text(text));
}
if (!items.isEmpty()) {
sendMessage(QQDatabase.checkFriend(qq),qq, items);
}
}
public void sendMessage(File imageFile, String text) {
sendMessage(true,defQQ,new Image(imageFile),new Text(text));
}
public void sendMessage(List<File> imgs, Long qq, String text) {
}
public void groupBan(long qqGroup, long user, int timer, ObjectInterface objectInterface) {
NapCatApi.getGroupApi().groupBan(qqGroup, user, timer).enqueue(new HttpCallback<BaseBean>() {
@Override
public void onResponse(Headers headers,int code, String status, BaseBean response, String rawResponse) {
if (objectInterface != null) {
objectInterface.out("1");
}
}
@Override
public void onFailure(Throwable throwable) {
if (objectInterface != null) {
objectInterface.out(null);
}
}
});
}
public void getShutUpList(long qqGroup, HttpCallback<List<GroupUserBean>> callback) {
NapCatApi.getGroupApi().getGroupUserList(qqGroup,true).enqueue(callback);
}
public void setGroupSpecialTitle(long group,
long user,
String title,
long duration) {
NapCatApi.getGroupApi().setGroupSpecialTitle(group, user, title, duration).enqueue(new HttpCallback<BaseBean>() {
@Override
public void onResponse(Headers headers,int code, String status, BaseBean response, String rawResponse) {
}
@Override
public void onFailure(Throwable throwable) {
}
});
}
public static void main(String[] args) {
getInstance();
JSONObject json = new JSONObject();
json.put("t1", 3234567890L);
System.out.println("json = " + json);
String tmp = json.toString();
JSONObject json2 = JSON.parseObject(tmp);
System.out.println("json2 = " + json2);
}
public void sendVersion() {
String localVersion = QQBotApplication.version;
String serverVersion = HttpTools.get("http://tools.yutou233.cn:8000/public/version.do?token=zIrsh9TUZP2lfRW753PannG49E7VJvor");
String msg = "本地版本:" + localVersion + "\n" + "服务器版本:" + serverVersion;
//String serverVersion = HttpTools.get("https://tools.yutou233.cn/public/version.do?token=zIrsh9TUZP2lfRW753PannG49E7VJvor");
String msg = "当前版本:" + localVersion ;
QQBotManager.getInstance().sendMessage(msg);
AppTools.sendServer("服务版本查询", msg);
// AppTools.sendServer("服务版本查询", msg);
}
public boolean isLogin() {
return true;
}
}

View File

@@ -1,7 +1,8 @@
package com.yutou.qqbot;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.qqbot.utlis.Log;
import com.yutou.qqbot.utlis.RedisTools;
import redis.clients.jedis.Jedis;
@@ -49,7 +50,7 @@ public class QQNumberManager {
}
public boolean addPower(Long qq, String power){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("power");
array.add(power);
json.put("power",array);
@@ -60,7 +61,7 @@ public class QQNumberManager {
public List<String> getPower(Long qq){
List<String> list=new ArrayList<>();
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("power");
for (Object power : array) {
list.add((String) power);
@@ -72,7 +73,7 @@ public class QQNumberManager {
public List<String> getUseModel(long qq) {
List<String> list=new ArrayList<>();
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("model");
for (Object power : array) {
list.add((String) power);
@@ -83,7 +84,7 @@ public class QQNumberManager {
}
public boolean delPower(Long qq, String power){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("power");
array.remove(power);
json.put("power",array);
@@ -93,7 +94,7 @@ public class QQNumberManager {
}
public boolean addUseModel(Long qq,Class<?> modelClass){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("model");
array.add(modelClass.getName());
json.put("model",array);
@@ -103,7 +104,7 @@ public class QQNumberManager {
}
public boolean delUseModel(Long qq,Class<?> modelClass){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("model");
array.remove(modelClass.getName());
json.put("model",array);
@@ -112,8 +113,9 @@ public class QQNumberManager {
return false;
}
public boolean isExistsPower(Long qq, String... power){
//1
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("power");
for (String key : power) {
if(!array.contains(key)){
@@ -126,14 +128,14 @@ public class QQNumberManager {
}
public boolean isGroup(Long qq){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
return json.getBoolean("group");
JSONObject json= JSON.parseObject(RedisTools.get(qq));
return json.getBooleanValue("group");
}
return false;
}
public boolean isUseModel(Long qq,Class<?> modelClass){
if(RedisTools.exists(qq,null)){
JSONObject json=JSONObject.parseObject(RedisTools.get(qq));
JSONObject json=JSON.parseObject(RedisTools.get(qq));
JSONArray array=json.getJSONArray("model");
return array.contains(modelClass.getName());
}

View File

@@ -0,0 +1,98 @@
package com.yutou.qqbot.bilibili;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AppUserTask {
private long isSurplus;
private long status;
private long progress;
private long target;
private Wallet wallet;
private List<WeekTask> weekTask = new ArrayList<>();
private long weekTotal;
private long weekGroup;
private DayTask dayTask;
public List<WeekTask> getWeekTask() {
if (weekTask == null) {
weekTask = new ArrayList<>();
}
return weekTask;
}
public static String toMessageFormat(AppUserTask oldTask, AppUserTask newTask) {
StringBuilder sb = new StringBuilder();
sb.append("当前电池数量:").append(String.format("%.2f → %.2f",
(double) oldTask.wallet.gold / 100,
(double) newTask.wallet.gold / 100)
).append("\n");
sb.append("当前银瓜子数量:").append(newTask.wallet.silver).append("\n");
sb.append("每日领取电池:").append(newTask.dayTask.toMessageFormat()).append("\n");
if (newTask.weekTask != null && !newTask.getWeekTask().isEmpty()) {
newTask.weekTask.forEach(task -> sb.append(task.toMessageFormat(newTask.weekTotal)).append("\n"));
}
return sb.toString();
}
public String toMessageFormat() {
StringBuilder sb = new StringBuilder();
sb.append("当前电池数量:").append(String.format("%.2f", (double) wallet.gold / 100)).append("\n");
sb.append("当前银瓜子数量:").append(wallet.silver).append("\n");
sb.append("每日领取电池:").append(dayTask.toMessageFormat()).append("\n");
weekTask.forEach(task -> sb.append(task.toMessageFormat(weekTotal)).append("\n"));
return sb.toString();
}
@Data
public static class DayTask {
private int status;
private long progress;
private long target;
public String toMessageFormat() {
return switch (getStatus()) {
case 0 -> "不可领取,需要发送弹幕数:" + getTarget() + ",进度:" + getProgress();
case 1 -> "进行中,需要发送弹幕数:" + getTarget() + ",进度:" + getProgress();
case 2 -> "可领取";
case 3 -> "已领取";
default -> "未知状态:" + this;
};
}
}
@Data
public static class Wallet {
private long gold;
private long silver;
}
// WeekTask.java
@Data
public static class WeekTask {
private long rewardNum;
private long minimalDay;
private int status;
private int id;
public String toMessageFormat(long totalNum) {
return switch (getStatus()) {
case 0 ->
"任务id:" + id + ",不可领取, 进度天数:" + totalNum + ",需要天数:" + minimalDay + ",任务奖励电池:" + rewardNum;
case 2 -> "任务id:" + id + ":可领取" + ",任务奖励电池:" + rewardNum;
case 3 -> "任务id:" + id + ":已领取" + ",任务奖励电池:" + rewardNum;
default -> "未知状态:" + this;
};
}
}
}

View File

@@ -0,0 +1,170 @@
package com.yutou.qqbot.bilibili;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class AssTools {
private final StringBuilder builder;
private String title;
private int y = 0;
private List<String> filters = new ArrayList<>();
private String alpha="80";
/**
* 弹幕转换ass
* @param title 标题
*/
public AssTools(String title) {
builder = new StringBuilder();
this.title=title;
initAssHeader();
}
/**
* 弹幕过滤器
* @param filter 过滤词
*/
public void addFilter(String... filter) {
filters.addAll(Arrays.asList(filter));
}
/**
* 弹幕透明度
* @param alpha 0 完全不透明 255 完全透明
*/
public void setAlpha(int alpha){
this.alpha=Integer.toHexString(alpha);
}
private void addBuilder(String txt) {
builder.append(txt).append("\n");
}
private void initAssHeader() {
addBuilder("[Script Info]");
addBuilder("Title: " + title);
addBuilder("Original Script: 本字幕由@yutou生成");
addBuilder("ScriptType: v4.00+");
addBuilder("Collisions: Normal");
addBuilder("PlayResX: 1920");
addBuilder("PlayResY: 1080");
addBuilder("Timer: 10.0000");
addBuilder("");
addBuilder("[V4+ Styles]");
addBuilder("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, ");
addBuilder("MarginL, MarginR, MarginV, Encoding");
addBuilder("Style: Fix,Microsoft YaHei UI,45,&H66FFFFFF,&H66FFFFFF,&H66000000,&H66000000,1,0,0,0,100,100,0,0,1,2,0,2,20,20,2,0");
addBuilder("Style: R2L,Microsoft YaHei UI,45,&H00FFFFFF,&H000000FF,&H00161616,&H00000000,0,0,0,0,100,100,0,0,1,2,0,2,20,20,20,1");
addBuilder("");
addBuilder("[Events]");
addBuilder("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text");
}
/**
* 保存弹幕文件
* @param savePath 存储路径
* @return 存储结果
*/
public boolean saveDanmu(String savePath) {
System.out.println("savePath = " + savePath);
File file = new File(savePath+File.separator+title+".ass");
FileWriter writer;
try {
if (file.exists()) {
if (!file.delete()) {
return false;
}
}
boolean mkdirs = file.mkdirs();
boolean delete = file.delete();
if (!mkdirs || !delete) {
return false;
}
if (!file.createNewFile()) {
return false;
}
writer = new FileWriter(file);
writer.write(builder.toString());
writer.flush();
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}finally {
}
return false;
}
/**
* 添加弹幕
* @param list 弹幕
*/
public void addDanmu(List<DanmuData> list) {
list.sort((o1, o2) -> {
if (o1.getTime() == o2.getTime()) {
return 0;
}
return o1.getTime() < o2.getTime() ? -1 : 1;
});
for (DanmuData danmuData : list) {
addDanmu(danmuData);
}
}
/**
* 添加弹幕
* @param danmuData 弹幕
*/
public void addDanmu(DanmuData danmuData) {
if (filters.contains(danmuData.getDanmu())) {
return;
}
addY();
long _time = danmuData.getTime();
long h = TimeUnit.MILLISECONDS.toHours(_time);
long m = TimeUnit.MILLISECONDS.toMinutes(_time) % 60;
long s = TimeUnit.MILLISECONDS.toSeconds(_time) % 60;
String sTime = String.format("%s:%s:%s.0",
new DecimalFormat("00").format(h),
new DecimalFormat("00").format(m),
new DecimalFormat("00").format(s));
if (s >= 52) {
s = (s + 8) - 60;
m++;
} else {
s += 8;
}
String eTime = String.format("%s:%s:%s.0",
new DecimalFormat("00").format(h),
new DecimalFormat("00").format(m),
new DecimalFormat("00").format(s));
float x1, x2;
x1 = 1920 + (danmuData.getDanmu().length() * 12.5f);
x2 = 0 - (danmuData.getDanmu().length() * 12.5f);
String ass = String.format("Dialogue: 0,%s,%s,R2L,,20,20,2,,{\\move(%.1f,%d,%.1f,%d)\\c&%s\\alpha&H%s}%s",
sTime,
eTime,
x1,
y,
x2,
y,
danmuData.getFontColorHex(),
alpha,
danmuData.getDanmu()
);
addBuilder(ass);
}
private void addY() {
y += 40;
if (y >= 1080) {
y = 40;
}
}
}

View File

@@ -0,0 +1,191 @@
package com.yutou.qqbot.bilibili;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.bilibili.BaseAPI;
import com.yutou.bilibili.api.LiveAPI;
import com.yutou.bilibili.api.VideoApi;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.models.BiliBili.BiliVideo;
import com.yutou.qqbot.utlis.AppTools;
import com.yutou.qqbot.utlis.BiliBiliWbiSign;
import com.yutou.qqbot.utlis.HttpTools;
import javax.net.ssl.HttpsURLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class BiliBiliAppUtils {
private static final String AppKey = "1d8b6e7d45233436";
private static final String AppSec = "560c52ccd288fed045859ed18bffd973";
private BiliBiliUtils biliUtils;
public BiliBiliAppUtils(Long qq) {
biliUtils = BiliBiliUtils.getInstance(qq);
}
public String getAccessToken() {
try {
String tmpUrl = BaseAPI.MCBBS_PNG;
String sign = AppTools.getMD5("api=" + tmpUrl + AppSec);
JSONObject get = biliUtils.http_get(BaseAPI.ACCESS_TOKEN+"?appkey=" + AppKey + "&api=" + tmpUrl + "&sign=" + sign);
assert get != null;
String uri = get.getJSONObject("data").getString("confirm_uri");
HttpsURLConnection connection = biliUtils.getBiliHttpGet(uri, biliUtils.getCookie());
connection.connect();
if (connection.getResponseCode() == 200) {
Map<String, String> params = HttpTools.getUrlParams(connection.getURL().toString());
return params.get("access_key");
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private Map<String, String> sign(Map<String, String> map) {
map.putAll(getDefaultBody());
map = sort(map);
StringBuilder builder = new StringBuilder();
for (String key : map.keySet()) {
builder.append(key).append("=").append(map.get(key)).append("&");
}
String param = builder.substring(0, builder.length() - 1);
map.put("sign", AppTools.getMD5(param + AppSec));
return map;
}
private Map<String, String> getDefaultBody() {
Map<String, String> map = new TreeMap<>();
map.put("access_key", getAccessToken());
map.put("actionKey", "appkey");
map.put("appkey", AppKey);
map.put("build", "7120200");
map.put("c_locale", "zh_CN");
map.put("channel", "xiaomi_cn_tv.danmaku.bili_20210930");
map.put("device", "android");
map.put("disable_rcmd", "0");
map.put("mobi_app", "android");
map.put("platform", "android");
map.put("s_locale", "zh_CN");
map.put("statistics", URLEncoder.encode("{\"appId\":1,\"platform\":3,\"version\":\"7.12.0\",\"abtest\":\"\"}", Charset.defaultCharset()));
map.put("ts", (System.currentTimeMillis() / 1000) + "");
return map;
}
private LinkedHashMap<String, String> sort(Map<String, String> map) {
return new LinkedHashMap<>(new TreeMap<>(map));
}
private Map<String, String> getHeaderMap() {
String md5_1 = AppTools.getMD5(System.currentTimeMillis() + "");
String md5_2 = AppTools.getMD5(System.currentTimeMillis() + "");
String trace_id = md5_1 + ":" + md5_2.substring(0, 16) + ":0:0";
Map<String, String> map = new TreeMap<>();
map.put("x-bili-mid", "96300");
map.put("x-bili-trace-id", trace_id);
map.put("x-bili-aurora-zone", "");
map.put("x-bili-aurora-eid", "WFICRlE=");
map.put("APP-KEY", "android64");
map.put("bili-http-engine", "cronet");
map.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
map.put("session_id", md5_1.substring(0, 8));
map.put("Host", "api.live.bilibili.com");
map.put("Connection", "keep-alive");
map.put("fp_local", md5_1 + md5_2);
map.put("fp_remote", md5_1 + md5_2);
map.put("env", "prod");
map.put("buvid", "XUF43FCF17D1747514C79C6D3D43B64C8D1B2");
map.put("Accept-Encoding", "gzip, deflate, br");
map.put("User-Agent", "Mozilla/5.0 BiliDroid/7.4.0 (bbcallen@gmail.com) os/android model/22061218C mobi_app/android build/7040300 channel/xiaomi_cn_tv.danmaku.bili_20210930 innerVer/7040310 osVer/12 network/2");
return map;
}
public AppUserTask getTaskProgress() {
JSONObject task = biliUtils.http_get(LiveAPI.LIVE_TASK_PROGRESS);
System.out.println("task = " + task);
assert task != null;
return task.getObject("data", AppUserTask.class);
}
private void setUserTaskProgress(int index) {
Map<String, String> map = new TreeMap<>();
map.put("target_id", "33989");
map.put("reward_index", index + "");
JSONObject httpGet = biliUtils.http(
LiveAPI.LIVE_SET_TASK_PROGRESS,
BiliBiliUtils.HTTP.POST,
HttpTools.toUrlParams(sign(map)),
getHeaderMap(),
BiliBiliUtils.RET_MODEL.JSON
);
System.out.println("任务 " + index + " :" + httpGet);
}
public AppUserTask startAppTask() {
AppUserTask task = getTaskProgress();
if (task.getDayTask().getStatus() == 2) {
setUserTaskProgress(0);
}
List<AppUserTask.WeekTask> taskList = task.getWeekTask();
taskList.forEach(weekTask -> {
if (weekTask.getStatus() == 2) {
setUserTaskProgress(weekTask.getId());
}
});
return task;
}
public static String getVideoAI(String url){
if(url.startsWith("https://b23.tv")){
url=b23ToUrl(url);
}
JSONObject videoInfo = new BiliVideo().getVideoInfo(url);
if(videoInfo==null){
return null;
}
String cid = videoInfo.getJSONObject("data").getString("cid");
TreeMap<String,String> body=new TreeMap<>();
body.put("cid",cid);
body.put("up_mid",videoInfo.getJSONObject("data").getJSONObject("owner").getString("mid"));
body.put("bvid",videoInfo.getJSONObject("data").getString("bvid"));
BiliBiliWbiSign.getWbiSign(body);
JSONObject object = BiliBiliUtils.getInstance(QQBotManager.defQQ)
.http_get(VideoApi.VIDEO_AI +"?"+HttpTools.toUrlParams(body));
if(object.getInteger("code")==0){
if(object.getJSONObject("data").getInteger("code")==0) {
return object.getJSONObject("data").getJSONObject("model_result").getString("summary");
}else{
return "没得省流";
}
}
return null;
}
public static String b23ToUrl(String url){
try {
HttpsURLConnection connection = BiliBiliUtils.getInstance(QQBotManager.defQQ).getBiliHttpGet(url, BiliBiliUtils.getInstance(QQBotManager.defQQ).getCookie());
connection.setInstanceFollowRedirects(false);
connection.connect();
if(connection.getResponseCode()==302){
connection.setConnectTimeout(5000);
return connection.getHeaderField("Location");
}
return connection.getURL().toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws Exception {
BiliBiliWbiSign.updateRawWbiKey();
String url="https://b23.tv/NtqDorB?share_medium=android&share_source=qq&bbid=XUDCA4BDD60B5853ACDC17794BFAEF91F874A&ts=1705470976484";
// url="https://www.bilibili.com/video/BV1fw411E75p/?buvid=XUDCA4BDD60B5853ACDC17794BFAEF91F874A&from_spmid=tm.recommend.0.0&is_story_h5=false&mid=7G8S%2B4e7nx6XSaU3oMQKXA%3D%3D&p=1&plat_id=116&share_from=ugc&share_medium=android&share_plat=android&share_session_id=ab27db6e-47a5-43b5-b0ec-b027bcfdeccc&share_source=QQ&share_tag=s_i&spmid=main.ugc-video-detail.0.0&timestamp=1705470976&unique_k=NtqDorB&up_id=1156809979";
String ai = getVideoAI(url);
System.out.println("ai = " + ai);
}
}

View File

@@ -0,0 +1,182 @@
package com.yutou.qqbot.bilibili;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.bilibili.api.MangaApi;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.interfaces.ObjectInterface;
import com.yutou.qqbot.utlis.HttpTools;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class BiliBiliManga {
public BiliBiliManga(long qq) {
biliUtils = BiliBiliUtils.getInstance(qq);
}
public static JSONObject sign() {
JSONObject body = new JSONObject();
body.put("platform", "android");
return BiliBiliUtils.getInstance(QQBotManager.defQQ).http_post(MangaApi.SIGN, HttpTools.toUrlParams(body));
}
private static JSONObject getListProductDate() {
return BiliBiliUtils.getInstance(QQBotManager.defQQ).http_post(MangaApi.LIST_PRODUCT_DATE, "");
}
private static boolean isPayMission = false;
private static Product missionProduct = new Product();
private static Timer mission = null;
private static BiliBiliUtils biliUtils = null;
private ObjectInterface anInterface = null;
public void addInterface(ObjectInterface objectInterface) {
anInterface = objectInterface;
}
public static boolean isPayMission() {
return isPayMission;
}
public static String getMission() {
return missionProduct + " 兑换数量:" + missionProduct.getPayAmount();
}
public static List<Product> getListProduct() {
List<Product> list = new ArrayList<>();
JSONObject product = getListProductDate();
if (product.getInteger("code") == 0) {
JSONArray array = product.getJSONArray("data");
for (Object o : array) {
JSONObject data = (JSONObject) o;
Product item = new Product();
item.setId(data.getInteger("id"));
item.setTitle(data.getString("title"));
item.setAmount(data.getInteger("amount"));
item.setRemain_amount(data.getInteger("remain_amount"));
item.setReal_cost(data.getInteger("real_cost"));
list.add(item);
}
}
return list;
}
public static int getMyPoint() {
JSONObject user = biliUtils.http_post(MangaApi.USER_POINT, "");
if (user != null && user.getInteger("code") == 0) {
return user.getJSONObject("data").getInteger("point");
}
return 0;
}
public JSONObject startPayMission(int id, int num) {
JSONObject json = new JSONObject();
if (isPayMission) {
json.put("code", 2);
json.put("msg", "任务正在进行:" + getMission());
return json;
}
if (biliUtils == null) {
json.put("code", -1);
json.put("msg", "B站未登录");
return json;
}
int userPoint = getMyPoint();
List<Product> list = getListProduct();
missionProduct = null;
for (Product product : list) {
if (product.getId() == id) {
missionProduct = product;
break;
}
}
if (missionProduct == null) {
json.put("code", -1);
json.put("msg", "未找到商品可能id有误 id:" + id);
return json;
}
if (num == -1) {
num = 99999;
}
int userPointNum = userPoint / missionProduct.getReal_cost();
num = Math.min(num, userPointNum);
if (num < missionProduct.getRemain_amount()) {
num = missionProduct.getRemain_amount();
}
missionProduct.setPayAmount(num);
JSONObject data = new JSONObject();
data.put("product_id", id);
data.put("product_num", num);
data.put("point", num * missionProduct.getReal_cost());
startPayMission(data);
isPayMission = true;
if (num == 0) {
json.put("code", 3);
json.put("msg", "商品无货,正在抢购");
} else {
json.put("code", 0);
json.put("msg", "任务创建成功:" + missionProduct + " 兑换数量:" + num);
}
return json;
}
private void startPayMission(JSONObject data) {
if (mission != null) {
mission.cancel();
}
mission = new Timer();
mission.schedule(new TimerTask() {
@Override
public void run() {
JSONObject post = biliUtils.http_post(MangaApi.PAY_MISSION, HttpTools.toUrlParams(data));
if (post == null) {
anInterface.out("网络请求失败,请查看日志");
cancel();
return;
}
if (post.getInteger("code") == 0) {
anInterface.out("兑换成功,任务已取消");
isPayMission = false;
cancel();
} else {
anInterface.out("[" + post.getInteger("code") + "]" + post.getString("msg"));
}
}
}, 0, 1000);
}
public void stopPayMission() {
if (isPayMission) {
isPayMission = false;
if (mission != null) {
mission.cancel();
}
}
}
public static void main(String[] args) {
// System.out.println(BiliBiliManga.sign());
BiliBiliUtils.getInstance(583819556L).sendLiveDanmu(33989,"学学这个");
}
@Data
public static class Product {
String title;
int id;
int remain_amount;
int real_cost;
int amount;
int payAmount;
@Override
public String toString() {
return "[ " + id + " ] " + title + " (" + remain_amount + "/" + amount + ") $" + real_cost;
}
}
}

View File

@@ -0,0 +1,444 @@
package com.yutou.qqbot.bilibili;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.bilibili.api.LiveAPI;
import com.yutou.bilibili.api.LoginAPI;
import com.yutou.bilibili.api.SignApi;
import com.yutou.bilibili.api.UserApi;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.interfaces.ObjectInterface;
import com.yutou.qqbot.utlis.*;
import org.brotli.dec.BrotliInputStream;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.zip.GZIPInputStream;
public class BiliBiliUtils {
private long qq;
private long oldBiliBiliHttpTime = 0;
public enum HTTP {
POST, GET
}
public enum RET_MODEL {
BYTE, JSON
}
public BiliBiliUtils(long qq) {
this.qq = qq;
}
public static BiliBiliUtils getInstance(long qq) {
return new BiliBiliUtils(qq);
}
public synchronized JSONObject http_get(String url) {
try {
Log.i("调用url = " + url);
HttpsURLConnection connection = getBiliHttpGet(url, getCookie());
BufferedInputStream stream = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = stream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
outputStream.flush();
}
String str = outputStream.toString(StandardCharsets.UTF_8);
outputStream.close();
try {
return JSON.parseObject(str);
} catch (Exception e) {
JSONObject json = new JSONObject();
json.put("html", str);
return json;
} finally {
stream.close();
connection.disconnect();
}
} catch (IOException e) {
//com.yutou.bilibili.Tools.Log.e(e);
e.printStackTrace();
}
return null;
}
public JSONObject http_login_getSid(String url) {
try {
Log.i("调用url = " + url);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
setConnection(null, connection);
connection.setRequestMethod("GET");
connection.connect();
BufferedInputStream stream = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = stream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
outputStream.flush();
}
List<String> cookie = null;
if (connection.getHeaderFields().containsKey("Set-Cookie")) {
cookie = connection.getHeaderFields().get("Set-Cookie");
}
String str = outputStream.toString(StandardCharsets.UTF_8);
outputStream.close();
try {
JSONObject json = JSON.parseObject(str);
if (cookie != null) {
StringBuilder ck = new StringBuilder();
for (String key : cookie) {
ck.append(";").append(key);
}
json.put("cookie", ck.toString());
}
return json;
} catch (Exception e) {
JSONObject json = new JSONObject();
json.put("html", str);
return json;
} finally {
stream.close();
connection.disconnect();
}
} catch (IOException e) {
//com.yutou.bilibili.Tools.Log.e(e);
e.printStackTrace();
}
return null;
}
public JSONObject http_post(String url, String body) {
return http(url, HTTP.POST, body, RET_MODEL.JSON);
}
public <T> T http(String url, HTTP model, String body, RET_MODEL ret_model) {
return http(url, model, body, null, ret_model);
}
public <T> T http(String url, HTTP model, String body, Map<String, String> headers, RET_MODEL ret_model) {
JSONObject json = null;
BufferedInputStream stream = null;
ByteArrayOutputStream outputStream = null;
OutputStream connectionOutputStream = null;
HttpURLConnection connection = null;
try {
if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
oldBiliBiliHttpTime = System.currentTimeMillis();
}
if (model == HTTP.POST) {
connection = getBiliHttpPost(url, getCookie());
} else {
if (body != null) {
if (url.contains("?")) {
url += "&" + body;
} else {
url += "?" + body;
}
body = null;
}
connection = getBiliHttpGet(url, getCookie());
}
if (headers != null) {
for (String key : headers.keySet()) {
connection.setRequestProperty(key, headers.get(key));
}
} else {
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
}
if (!StringUtils.isEmpty(body)) {
connectionOutputStream = connection.getOutputStream();
connectionOutputStream.write(body.getBytes(StandardCharsets.UTF_8));
connectionOutputStream.flush();
}
connection.connect();
if (connection.getResponseCode() == 400) {
return null;
}
if (connection.getContentEncoding() != null && connection.getContentEncoding().contains("gzip")) {
stream = new BufferedInputStream(new GZIPInputStream(connection.getInputStream()));
} else if (connection.getContentEncoding() != null && connection.getContentEncoding().contains("br")) {
stream = new BufferedInputStream(new BrotliInputStream(connection.getInputStream()));
} else {
stream = new BufferedInputStream(connection.getInputStream());
}
outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = 0, size;
while ((len = stream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
outputStream.flush();
}
if (ret_model == RET_MODEL.BYTE) {
return (T) outputStream.toByteArray();
}
String str = outputStream.toString(StandardCharsets.UTF_8);
try {
json = JSON.parseObject(str);
json.put("cookie", connection.getHeaderField("Set-Cookie"));
return (T) json;
} catch (Exception e) {
json = new JSONObject();
json.put("html", str);
json.put("cookie", connection.getHeaderField("Set-Cookie"));
return (T) json;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (stream != null) {
stream.close();
}
if (outputStream != null) {
outputStream.close();
}
if (connectionOutputStream != null) {
connectionOutputStream.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (Exception ignored) {
}
}
return null;
}
public String getCookie() {
if (StringUtils.isEmpty(ConfigTools.readFile(new File(qq + "_bilibili.cookie")))) {
return "";
}
JSONObject json = JSON.parseObject(ConfigTools.readFile(new File(qq + "_bilibili.cookie")));
StringBuilder builder = new StringBuilder();
for (String s : json.keySet()) {
builder.append(s).append("=").append(json.getString(s)).append(";");
}
return builder.toString();
}
public HttpURLConnection getBiliHttpPost(String url, String cookie) throws Exception {
if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
oldBiliBiliHttpTime = System.currentTimeMillis();
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
setConnection(cookie, connection);
return connection;
}
public HttpsURLConnection getBiliHttpGet(String url, String cookie) throws IOException {
if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
oldBiliBiliHttpTime = System.currentTimeMillis();
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
if (cookie != null) {
setConnection(cookie, connection);
}
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
return connection;
}
public File download(final String url, final String saveName, boolean isProxy) {
File jar = null;
try {
File savePath = new File(HttpTools.downloadPath + saveName);
Proxy proxy = null;
if (!savePath.exists()) {
savePath.mkdirs();
}
savePath.delete();
Log.i("DOWNLOAD", "下载文件:" + url + " 保存文件:" + saveName);
if (isProxy) {
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
}
HttpsURLConnection connection;
if (isProxy) {
connection = (HttpsURLConnection) new URL(url).openConnection(proxy);
} else {
connection = (HttpsURLConnection) new URL(url).openConnection();
}
setConnection(getCookie(), connection);
InputStream inputStream = connection.getInputStream();
jar = new File(HttpTools.downloadPath + saveName + "_tmp.tmp");
jar.createNewFile();
Log.i("DOWNLOAD", "临时保存文件:" + jar.getAbsolutePath());
OutputStream outputStream = new FileOutputStream(jar);
byte[] bytes = new byte[1024];
double size = connection.getContentLength();
double downSize = 0;
int len;
while ((len = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, len);
downSize += len;
}
outputStream.close();
inputStream.close();
File oldJar = new File(HttpTools.downloadPath + saveName);
if (oldJar.exists()) {
oldJar.delete();
}
jar.renameTo(oldJar);
Log.i("DOWNLOAD", "实际保存:" + oldJar.getAbsolutePath() + " " + oldJar.getName());
return oldJar;
} catch (Exception e) {
e.printStackTrace();
if (jar != null) {
jar.delete();
}
}
return null;
}
public void download_ffmpeg(final List<String> url, final String saveName) {
new Thread(() -> {
StringBuilder builder = new StringBuilder();
builder.append(ConfigTools.load(ConfigTools.CONFIG, ConfigTools.FFMPEG, String.class)).append(" ");
/* builder.append("-user_agent").append(" ");
builder.append("\"").append("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36 Referer:https://live.bilibili.com").append("\"").append(" ");
builder.append("-cookies").append(" ");
builder.append("\"").append(getCookie()).append("\"").append(" ");
builder.append("-headers").append(" ");
builder.append("\"").append("Referer:https://live.bilibili.com").append("\"").append(" ");*/
for (String _url : url) {
builder.append("-i").append(" ");
builder.append("\"").append(_url).append("\"").append(" ");
}
builder.append("-vcodec").append(" ");
builder.append("copy").append(" ");
builder.append("-acodec").append(" ");
builder.append("copy").append(" ");
builder.append("-threads").append(" ");
builder.append("8").append(" ");
// builder.append("-y").append(" ");
builder.append(new File(HttpTools.downloadPath + saveName + ".mp4").getAbsolutePath()).append(" ");
System.out.println(builder);
AppTools.exec(builder.toString(), new ObjectInterface() {
@Override
public void out(String data) {
super.out(data);
System.out.println("data = " + data);
}
}, false, false);
}).start();
}
private void setConnection(String cookie, HttpURLConnection connection) {
connection.addRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
connection.addRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
connection.addRequestProperty("Cache-Control", "max-age=0");
connection.setRequestProperty("Referer", "https://www.bilibili.com");
connection.addRequestProperty("Connection", "keep-alive");
connection.addRequestProperty("Upgrade-Insecure-Requests", "1");
if (!StringUtils.isEmpty(cookie)) {
connection.addRequestProperty("Cookie", cookie);
}
connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
}
public JSONObject getLoginInfo() {
JSONObject jsonObject = http_get(UserApi.NAV);
if (jsonObject == null) {
jsonObject = new JSONObject();
jsonObject.put("code", "-1");
jsonObject.put("data", new JSONObject());
}
return jsonObject;
}
public static void main(String[] args) {
/* String url="https://xy218x85x123x8xy.mcdn.bilivideo.cn:4483/upgcxcode/12/12/17281212/17281212-16-80.flv?e=ig8euxZM2rNcNbNBhbdVhwdlhbUghwdVhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1660538573&gen=playurlv2&os=mcdn&oi=2936701972&trid=00006f9623cac1514d8ea18fba3a15a756cau&mid=96300&platform=pc&upsig=25ddd1da610960e8e1d2e80dc97c2361&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,mid,platform&mcdnid=11000101&bvc=vod&nettype=0&orderid=0,2&agrr=1&bw=253116&logo=A0000400&requestFrom=BILIBILI_HELPER_2.5.8";
File file=download(url,"16.mp4",false);
System.out.println("file.getAbsolutePath() = " + file.getAbsolutePath());*/
/* System.out.println(getLiveRoom(42062));
System.out.println("--------------------------------------------");
System.out.println(getUserInfo(730732));*/
JSONObject sign = new BiliBiliUtils(583819556).getUserInfo(96300);
System.out.println("sign = " + sign);
}
public boolean sendLiveDanmu(long roomId, String msg) {
JSONObject body = new JSONObject();
body.put("msg", msg);
body.put("roomid", roomId);
body.put("color", 16777215);
body.put("fontsize", 25);
body.put("rnd", System.currentTimeMillis() / 1000);
body.put("csrf", BiliLogin.getCookieToken(qq));
body.put("csrf_token", BiliLogin.getCookieToken(qq));
JSONObject post = http_post(LiveAPI.LIVE_SEND_DANMU, HttpTools.toUrlParams(body));
return post.getInteger("code") == 0;
}
public String liveSignIn() {
//{"code":0,"data":{"coin":1,"gold":19500,"silver":106394,"tid":"Silver2Coin22101413201169763005873"},"message":"兑换成功"}
JSONObject body = new JSONObject();
body.put("csrf", BiliLogin.getCookieToken(qq));
body.put("csrf_token", BiliLogin.getCookieToken(qq));
JSONObject toCoin = http_post(SignApi.LIVE_SIGN_COIN, HttpTools.toUrlParams(body));
JSONObject liveSign =JSONObject.parseObject("{\"message\":\"已停用\"}"); //http_get(SignApi.LIVE_SIGN);
JSONObject vipSign = http_post(SignApi.VIP_SIGN, null);
return "银瓜子兑换硬币:" + toCoin.getString("message") + "|" + "直播签到:" + liveSign.getString("message") + "|大会员中心签到:" + vipSign.getString("message");
}
public JSONObject getLiveRoom(int roomId) {
JSONObject body = new JSONObject();
body.put("room_id", roomId);
body.put("csrf", BiliLogin.getCookieToken(qq));
body.put("csrf_token", BiliLogin.getCookieToken(qq));
return http_post(LiveAPI.LIVE_ROOM_INFO, HttpTools.toUrlParams(body));
}
public JSONObject getUserInfo(int mid) {
TreeMap<String, String> body = new TreeMap<>();
body.put("mid", mid + "");
BiliBiliWbiSign.getWbiSign(body);
return http_get(UserApi.USER_INFO_V2 + "?" + HttpTools.toUrlParams(body));
}
public boolean checkLiveRoom(int roomId) {
JSONObject post = getLiveRoom(roomId);
return post.getInteger("code") == 0;
}
}

View File

@@ -0,0 +1,110 @@
package com.yutou.qqbot.bilibili;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.bilibili.api.LoginAPI;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.utlis.*;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
public class BiliLogin {
BiliBiliUtils biliUtils;
private long qq;
public BiliLogin(Long qq) {
biliUtils = BiliBiliUtils.getInstance(qq);
this.qq = qq;
}
public JSONObject login() {
JSONObject login = JSON.parseObject(HttpTools.get(LoginAPI.LOGIN_QRCODE));
JSONObject json = new JSONObject();
System.out.println("login = " + login);
json.put("code", login.getInteger("code"));
json.put("url", login.getJSONObject("data").getString("url"));
new Thread(() -> waitLogin(login.getJSONObject("data").getString("qrcode_key"))).start();
return json;
}
public void loginAsQQ() {
String url = login().getString("url");
File code = QRCodeUtils.createQRCode("bili_login", url);
QQBotManager.getInstance().sendMessage(code, qq, "B站未登录,请扫码登陆后再试");
}
public void waitLogin(String oauthKey) {
long time = System.currentTimeMillis();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
String bd = "gourl=https%3A%2F%2Fpassport.bilibili.com%2Fajax%2FminiLogin%2Fredirect&oauthKey=" + oauthKey;
if ((System.currentTimeMillis() - time) > 5 * 60 * 1000) {
cancel();
return;
}
JSONObject json = biliUtils.http_login_getSid(LoginAPI.LOGIN_QRCODE_POLL + "?qrcode_key=" + oauthKey);
Log.i("B站登陆", json.toJSONString());
if (json.getInteger("code") == 0 && json.getJSONObject("data").getInteger("code") == 0) {
String[] split = json.getString("cookie").split(";");
JSONObject ck = new JSONObject();
for (String string : split) {
if (!ck.containsKey(string) && !StringUtils.isEmpty(string) && string.contains("=")) {
String key = string.split("=")[0].trim();
String value = string.split("=")[1].trim();
if (key.contains("Expires")) {
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getDefault());
Date date = sdf.parse(value, new ParsePosition(0));
value = String.valueOf(date.getTime() / 1000);
}
ck.put(key, value);
}
}
ck.put("gourl", bd);
ConfigTools.saveFile(new File(qq + "_bilibili.cookie"), ck.toJSONString());
cancel();
}
}
}, 1000, 3000);
}
public boolean testLogin() {
if (biliUtils == null) {
return false;
}
JSONObject jsonObject = biliUtils.getLoginInfo();
return jsonObject.getInteger("code") == 0;
}
public static String getCookieToken(Long qq) {
if (StringUtils.isEmpty(ConfigTools.readFile(new File(qq + "_bilibili.cookie")))) {
return null;
}
JSONObject json = JSON.parseObject(ConfigTools.readFile(new File(qq + "_bilibili.cookie")));
return json.getString("bili_jct");
}
public static void main(String[] args) throws ParseException {
String http = "{\"code\":0,\"message\":\"0\",\"ttl\":1,\"data\":{\"url\":\"https://passport.biligame.com/x/passport-login/web/crossDomain?DedeUserID=96300&DedeUserID__ckMd5=c506a12068157a3a&Expires=1720252437&SESSDATA=c383a8e0,1720252437,9ba5c*11CjCBp3_j-6zYtK27tzUVrmFZNgjyeDW6pcdfmRBJU5cVfz4OhVmujjKCZsGAkXL6ll8SVnplZ2JONlBleHdFOGgzUzNJYUxIbzJwRVhTYVM2LWVuQnJyQVQxQnRWTUFZbUYybV95Y1RELTdGeF9mNlpXV3RDTjdsMVBaYkhxZGZyblRkTUJCMGV3IIEC&bili_jct=e786885293c24eb7198dc0538b56d6d8&gourl=https%3A%2F%2Fwww.bilibili.com\",\"refresh_token\":\"347b83e7c4a1e24f4681f06f28f71b11\",\"timestamp\":1704700437058,\"code\":0,\"message\":\"\"},\"cookie\":\";SESSDATA=c383a8e0%2C1720252437%2C9ba5c%2A11CjCBp3_j-6zYtK27tzUVrmFZNgjyeDW6pcdfmRBJU5cVfz4OhVmujjKCZsGAkXL6ll8SVnplZ2JONlBleHdFOGgzUzNJYUxIbzJwRVhTYVM2LWVuQnJyQVQxQnRWTUFZbUYybV95Y1RELTdGeF9mNlpXV3RDTjdsMVBaYkhxZGZyblRkTUJCMGV3IIEC; Path=/; Domain=bilibili.com; Expires=Sat, 06 Jul 2024 07:53:57 GMT; HttpOnly; Secure;bili_jct=e786885293c24eb7198dc0538b56d6d8; Path=/; Domain=bilibili.com; Expires=Sat, 06 Jul 2024 07:53:57 GMT;DedeUserID=96300; Path=/; Domain=bilibili.com; Expires=Sat, 06 Jul 2024 07:53:57 GMT;DedeUserID__ckMd5=c506a12068157a3a; Path=/; Domain=bilibili.com; Expires=Sat, 06 Jul 2024 07:53:57 GMT;sid=ger7871m; Path=/; Domain=bilibili.com; Expires=Sat, 06 Jul 2024 07:53:57 GMT\"}";
JSONObject body = JSON.parseObject(http);
BiliLogin login = new BiliLogin(583819556L);
boolean testLogin = login.testLogin();
System.out.println("testLogin = " + testLogin);
System.out.println(BiliBiliUtils.getInstance(583819556L).getLoginInfo());
//JSONObject json = login.login();
//System.out.println("json = " + json);
// QRCodeUtils.createQRCode("bili_login", json.getString("url"));
}
}

View File

@@ -0,0 +1,26 @@
package com.yutou.qqbot.bilibili;
import lombok.Data;
import java.util.Date;
@Data
public class DanmuData {
private int id;
private int model;//13 滚动弹幕 4 底端弹幕 5 顶端弹幕 6 逆向弹幕 7 精准定位 8 高级弹幕
private int fontSize;
private int fontColor;
private long time;
private String uCode;
private String danmu;
private long uid;
private String uname;
public Date getTimeDate() {
return new Date(time);
}
public String getFontColorHex() {
return Integer.toHexString(fontColor);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
package com.yutou.qqbot.data;
public class MessageChainBuilder {
StringBuilder sb;
public MessageChainBuilder() {
sb=new StringBuilder();
}
public MessageChainBuilder append(String s){
sb.append(s);
return this;
}
public MessageChainBuilder append(Object o){
sb.append(o.toString());
return this;
}
@Override
public String toString() {
return sb.toString();
}
}

View File

@@ -0,0 +1,28 @@
package com.yutou.qqbot.data.baidu;
import lombok.Data;
@Data
public class Message {
private String role = "user";
private String content;
public Message() {
}
public boolean checkIsUser() {
return "user".equals(role);
}
public static Message create(String message) {
return create(message, false);
}
public static Message create(String message, boolean isGTP) {
Message msg = new Message();
msg.content = message;
msg.role = isGTP ? "assistant" : "user";
return msg;
}
}

View File

@@ -0,0 +1,17 @@
package com.yutou.qqbot.data.baidu;
import lombok.Data;
@Data
public class ResponseMessage {
private String id;
private String object;
private long created;
private String result;
private boolean isTruncated;
private boolean needClearHistory;
private Message usage;
public ResponseMessage() {
}
}

View File

@@ -0,0 +1,50 @@
package com.yutou.qqbot.data.bili;
import lombok.Data;
@Data
public class EPInfo {
private int code;
private String message;
private MediaResult result;
@Data
public static class MediaResult {
private Media media;
// getters and setters
}
@Data
public static class Media {
private String cover;
private String horizontal_picture;
private int media_id;
private NewEp new_ep;
private Rating rating;
private int season_id;
private String share_url;
private String title;
private int type;
private String type_name;
// getters and setters
}
@Data
public static class NewEp {
private int id;
private String index;
private String index_show;
// getters and setters
}
@Data
public static class Rating {
private int count;
private double score;
// getters and setters
}
}

View File

@@ -0,0 +1,90 @@
package com.yutou.qqbot.data.gpt;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.util.List;
@Data
public class OpenAiBean {
@JSONField(name = "id")
private String id;
@JSONField(name = "choices")
private List<Choice> choices;
@JSONField(name = "tool_calls")
private List<ToolCall> toolCalls;
@JSONField(name = "usage")
private Usage usage;
@JSONField(name = "created")
private long created;
@JSONField(name = "model")
private String model;
@JSONField(name = "object")
private String object;
@JSONField(name = "system_fingerprint")
private String systemFingerprint;
@Data
public static class Choice {
@JSONField(name = "index")
private int index;
@JSONField(name = "message")
private Message message;
@JSONField(name = "finish_reason")
private String finishReason;
}
@Data
public static class Message {
@JSONField(name = "role")
private String role;
@JSONField(name = "content")
private String content;
@JSONField(name = "reasoning_content")
private String reasoningContent;
}
@Data
public static class ToolCall {
@JSONField(name = "id")
private String id;
@JSONField(name = "type")
private String type;
@JSONField(name = "function")
private Function function;
}
@Data
public static class Function {
@JSONField(name = "name")
private String name;
@JSONField(name = "arguments")
private String arguments;
}
@Data
public static class Usage {
@JSONField(name = "prompt_tokens")
private int promptTokens;
@JSONField(name = "completion_tokens")
private int completionTokens;
@JSONField(name = "total_tokens")
private int totalTokens;
}
}

View File

@@ -0,0 +1,49 @@
package com.yutou.qqbot.data.jianr;
import lombok.Data;
import java.util.List;
@Data
public class AndroidDevice {
String title;
String deviceId;
DeviceDisplay androidDevice;
List<GameDisplay> deviceDisplay;
@Data
public static class DeviceDisplay {
int width, height;
}
@Data
public static class GameDisplay {
String title;
double width, height;
Vector2D start, end;
public double getWidth() {
return end.getX() - start.getX();
}
public double getHeight() {
return end.getY() - start.getY();
}
public void setEnabledRandom(boolean enabled) {
if(enabled){
start.setEnableRandomY(true);
start.setEnableRandomX(true);
end.setEnableRandomX(true);
end.setEnableRandomY(true);
}else{
start.setEnableRandomX(false);
start.setEnableRandomY(false);
end.setEnableRandomY(false);
end.setEnableRandomX(false);
}
}
}
}

View File

@@ -0,0 +1,38 @@
package com.yutou.qqbot.data.jianr;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class JianRScriptData {
private String name;
private String device;
private List<Script> run;
public void addRun(Script script) {
if(run==null){
run=new ArrayList<>();
}
run.add(script);
}
@Data
public static class Script {
private String name;
private int nextWaitTime;
private int randomNextWaitTime;
private String model;
private int x;
private int y;
private int rx;
private int ry;
public static class ScriptModel {
public static final String CLICK = "click";
public static final String WAIT = "wait";
}
}
}

View File

@@ -0,0 +1,28 @@
package com.yutou.qqbot.data.jianr;
import lombok.Data;
import java.util.List;
@Data
public class JianRScriptV2Data {
private String title;
private List<Script> script;
@Data
public static class Script {
private String title;
private String activity;
private int nextWaitTime;
private int randomNextWaitTime;
}
public static class ScriptModel {
public static final String MAP = "map";
public static final String attack = "attack";
public static final String formationType = "formationType";
public static final String dialog_go = "dialog_go";
public static final String dialog_back = "dialog_back";
public static final String dialog_assets = "dialog_assets";
public static final String none = "none";
}
}

View File

@@ -0,0 +1,45 @@
package com.yutou.qqbot.data.jianr;
import lombok.Data;
import java.util.Random;
@Data
public class Vector2D {
double x, y;
boolean enableRandomX, enableRandomY;
boolean absRandomX, absRandomY;
int randomNumX, randomNumY;
public double getX() {
if (isEnableRandomX()) {
double tmp = new Random().nextDouble(-randomNumX, randomNumX);
if (isAbsRandomX()) {
return Math.abs(tmp) + x;
} else {
return tmp + x;
}
}
return x;
}
public double getNotRandomY() {
return y;
}
public double getNotRandomX() {
return x;
}
public double getY() {
if(isEnableRandomY()){
double tmp = new Random().nextDouble(-randomNumY, randomNumY);
if (isAbsRandomY()) {
return Math.abs(tmp) + y;
} else {
return tmp + y;
}
}
return y;
}
}

View File

@@ -0,0 +1,160 @@
package com.yutou.qqbot.gpt;
import com.yutou.qqbot.data.baidu.Message;
import com.yutou.qqbot.utlis.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbsGPTManager {
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> currentTask;
protected static final AtomicInteger MAX_MESSAGE = new AtomicInteger(20);
protected final ConcurrentHashMap<String, List<Message>> msgMap= new ConcurrentHashMap<>();
// 新增锁映射表
protected final ConcurrentHashMap<String, AtomicBoolean> userLocks = new ConcurrentHashMap<>();
protected String model ;
/**
* 清除与GPT管理器相关的所有缓存或状态信息。
*/
/**
* 这里确实是需要清空所有数据
*/
public void clear() { // 添加同步
msgMap.clear();
for (AtomicBoolean value : userLocks.values()) {
value.set(false);
}
userLocks.forEachValue(1, atomicBoolean -> atomicBoolean.set(false));
userLocks.clear();
}
/**
* 发送消息到指定用户。
*
* @param user 接收消息的用户标识符。
* @param message 要发送的消息内容。
* @return 包含消息发送结果的Message对象。
*/
public abstract Message sendMessage(String user, String message);
public abstract Message sendTmpMessage(String user, String message, String tmpModel);
/**
* 将文本转换为图像。
*
* @param user 用户标识符。
* @param text 要转换为图像的文本内容。
* @return 包含生成图像的File对象。
*/
public abstract File textToImage(String user, String text);
/**
* 将图像转换为文本。
*
* @param user 用户标识符。
* @param file 包含要转换为文本的图像文件。
* @return 提取的文本内容。
*/
public abstract String imageToText(String user, File file);
/**
* 获取当前使用的GPT版本信息。
*
* @return GPT版本字符串。
*/
public abstract String getGPTVersion();
/**
* 设置最大消息数量。
*
* @param count 最大消息数量。
* @return 设置后的最大消息数量。
*/
public abstract int setMaxMessageCount(int count);
public List<Message> getMessageList(String user){
/*List<Message> list = msgMap.computeIfAbsent(user, k -> Collections.synchronizedList(new ArrayList<>()));
// 限制历史消息的最大数量
synchronized (list) {
if (list.size() >= MAX_MESSAGE.get()) {
int removeCount = list.size() - MAX_MESSAGE.get() + 1; // 腾出空间给新消息
list.subList(0, removeCount).clear();
}
}
return list;*/
return new ArrayList<>();
}
/**
* 根据指定的类获取相应的GPT管理器实例。
*
* @param tClass GPT管理器的具体实现类。
* @return GPT管理器实例。
*/
public static <T extends AbsGPTManager> AbsGPTManager getManager(Class<?> tClass) {
if (tClass == BaiduGPTManager.class) {
return BaiduGPTManager.getManager();
}else if(tClass== SiliconGPTManager.class){
return SiliconGPTManager.getInstance();
}
return new AbsGPTManager() {
@Override
public void clear() {
}
@Override
public Message sendMessage(String user, String message) {
return null;
}
@Override
public Message sendTmpMessage(String user, String message, String tmpModel) {
return null;
}
@Override
public File textToImage(String user, String text) {
return null;
}
@Override
public String imageToText(String user, File file) {
return "";
}
@Override
public String getGPTVersion() {
return "";
}
@Override
public int setMaxMessageCount(int count) {
return 0;
}
};
}
public AbsGPTManager setModel(String model) {
this.model=model;
return this;
}
public void sendMessageAndScheduleClear() {
// 取消当前的定时任务(如果存在)
if (currentTask != null && !currentTask.isCancelled()) {
currentTask.cancel(false);
}
// 重新调度一个新的定时任务,一小时后执行
currentTask = scheduler.schedule(() -> {
clear();
currentTask = null; // 清空当前任务引用
}, 1, TimeUnit.HOURS);
}
}

View File

@@ -0,0 +1,240 @@
package com.yutou.qqbot.gpt;
import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.QianfanV2;
import com.baidubce.qianfan.model.chat.ChatResponse;
import com.baidubce.qianfan.model.chat.v2.response.ResponseV2;
import com.baidubce.qianfan.model.image.Image2TextResponse;
import com.baidubce.qianfan.model.image.Text2ImageResponse;
import com.yutou.qqbot.data.baidu.Message;
import com.yutou.qqbot.utlis.ConfigTools;
import com.yutou.qqbot.utlis.Log;
import com.yutou.qqbot.utlis.StringUtils;
import lombok.val;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class BaiduGPTManager extends AbsGPTManager {
private static final String AppID = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_APPID, String.class);
private static final String ApiKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_API_KEY, String.class);
//ConfigTools.load操作可以确保获取到相关参数所以无需关心
private static final String AccessKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_ACCESS_KEY, String.class);
private static final String SecretKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_SECRET_KEY, String.class);
private final static String modelFor40 = "ernie-4.0-8k";
private final static String modelFor35 = "ernie-speed-128k";
private final Qianfan qianfan;
private final QianfanV2 qianfanV2;
private BaiduGPTManager() {
qianfan = new Qianfan(AccessKey, SecretKey);
qianfanV2 = new Qianfan(AccessKey, SecretKey).v2();
String savedVersion = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, String.class);
if (StringUtils.isEmpty(savedVersion) || (!"3.5".equals(savedVersion) && !"4.0".equals(savedVersion))) {
savedVersion = "3.5";
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, savedVersion);
}
model = "3.5".equals(savedVersion) ? modelFor35 : modelFor40;
}
private static volatile BaiduGPTManager manager;
public static BaiduGPTManager getManager() {
if (manager == null) {
synchronized (BaiduGPTManager.class) {
if (manager == null) {
manager = new BaiduGPTManager();
}
}
}
return manager;
}
@Override
public int setMaxMessageCount(int count) {
MAX_MESSAGE.set(count);
return count;
}
// 这个是官方的示例代码,表示连续对话
private static void exampleChat() {
Qianfan qianfan = new Qianfan();
ChatResponse response = qianfan.chatCompletion()
// 设置需要使用的模型与endpoint同时只能设置一种
.model("ERNIE-Bot")
// 通过传入历史对话记录来实现多轮对话
.addMessage("user", "你好!你叫什么名字?")
.addMessage("assistant", "你好我是文心一言英文名是ERNIE Bot。")
// 传入本轮对话的用户输入
.addMessage("user", "刚刚我的问题是什么?")
.execute();
System.out.println("输出内容:" + response.getResult());
}
/**
* 发送消息方法
* 该方法用于处理用户发送的消息,并返回相应的回复消息
* 它通过用户锁来限制每个用户同时只能有一个请求正在处理中
*
* @param user 用户标识符,用于区分不同的用户
* @param message 用户发送的消息内容
* @return 返回处理后的消息对象,包含回复内容和是否为回复消息的标记
*/
@Override
public Message sendMessage(String user, String message) {
return sendTmpMessage(user, message, null);
}
@Override
public Message sendTmpMessage(String user, String message, String tmpModel) {
boolean isTmp = (tmpModel != null);
// 获取或创建用户锁
AtomicBoolean lock = userLocks.computeIfAbsent(user, k -> new AtomicBoolean(false));
// 尝试加锁(如果已被锁定则立即返回提示)
if (!lock.compareAndSet(false, true)) {
return Message.create("您有请求正在处理中,请稍后再试", true);
}
if (!isTmp) {
tmpModel = model;
}
try {
List<Message> list = getMessageList(user);
if(!isTmp) {
list.add(Message.create(message));
}
val builder = qianfanV2.chatCompletion()
.model(tmpModel);
Log.i("GPT收到消息",isTmp,list.size());
if (!isTmp) {
StringBuilder sb = new StringBuilder();
for (Message msg : list) {
Log.i("GPT获取历史消息",msg.getRole(),msg.getContent());
builder.addMessage(msg.getRole(), msg.getContent());
sb.append(msg.getRole()).append(":").append(msg.getContent()).append("\n");
}
Log.d(sb.toString());
} else {
val mt = Message.create(message);
builder.addMessage(mt.getRole(),mt.getContent());
}
ResponseV2 chatResponse = qianfanV2.chatCompletion(builder.build());
Message response = Message.create(chatResponse.getChoices().get(0).getMessage().getContent(), true);
if (isTmp) {
synchronized (list) {
list.add(response);
if (list.size() > MAX_MESSAGE.get()) {
int overflow = list.size() - MAX_MESSAGE.get();
list.subList(0, overflow).clear();
}
}
}
// msgMap.put(user, list);
return response;
} catch (Exception e) {
Log.e(e, message);
return Message.create("请求失败,请重试", true);
} finally {
lock.set(false);
userLocks.remove(user, lock);
}
}
/**
* 将文本转换为图像文件
* 该方法使用预训练的AI模型将给定的文本转换为图像并将其保存为文件
*
* @param user 用户标识符,用于为生成的图像文件命名
* @param text 要转换为图像的文本
* @return 返回生成的图像文件对象如果转换过程中发生错误则返回null
*/
@Override
public File textToImage(String user, String text) {
try {
// 使用QianFan的text2Image方法将文本转换为图像数据
Text2ImageResponse response = qianfan.text2Image()
.prompt(text)
.execute();
// 获取转换后的图像数据以Base64编码的图像字符串形式
val b64Image = response.getData().get(0).getB64Image();
// 将Base64编码的图像数据转换为图像文件
// 创建一个临时目录下的图像文件,文件名包含用户标识符和当前时间戳,以确保唯一性
val imageFile = new File("tmp" + File.separator + user + "_" + System.currentTimeMillis() + ".png");
try (val inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(b64Image))) {
// 将解码后的图像数据复制到图像文件中,替换现有文件
Files.copy(inputStream, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return imageFile;
}
} catch (Exception e) {
// 如果在图像文件生成过程中发生错误,记录错误信息
Log.e(e);
}
// 如果发生错误返回null
return null;
}
/**
* 将图片转换为文本描述
*
* @param user 使用该功能的用户标识
* @param file 要转换的图片文件
* @return 转换后的文本描述如果转换失败则返回null
*/
@Override
public String imageToText(String user, File file) {
// 将file文件转换成base64的代码
try {
// 读取文件内容并转换为Base64编码
val base64 = Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
// 调用图像转文本的API
Image2TextResponse response = qianfan.image2Text()
.image(base64)
.prompt("请描述这张图片中的主要内容和细节,以及它们之间的关系\n")
.execute();
String translationPrompt = "将以下英文内容严格翻译为简体中文不要解释、不要添加额外内容保留专业术语和名称如Star Wars保持英文\n" + response.getResult();
// 获取API返回的结果
return sendMessage("bot", translationPrompt).getContent();
} catch (Exception e) {
// 异常处理:记录错误日志
Log.e(e);
}
// 如果发生异常返回null
return null;
}
@Override
public AbsGPTManager setModel(String model) {
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, model);
return super.setModel(model);
}
@Override
public String getGPTVersion() {
return model;
}
public static void main(String[] args) throws Exception {
// BaiduGPTManager.getManager().textToImage("user","画一个猫娘,用二次元动画画风,她是粉色头发,坐在地上");
// BaiduGPTManager.getManager().imageToText("user",new File("test.png"));
// Message message = BaiduGPTManager.getManager().sendMessage("user", "现在假设小猪等于1,小猴等于2");
// System.out.println(message.getContent());
// message = BaiduGPTManager.getManager().sendMessage("user", "那么小猪加上小猴等于多少?");
// System.out.println(message.getContent());
System.out.println(BaiduGPTManager.getManager().sendMessage("user", "分析这个网页链接的页面内容,而非链接本身:https://www.bilibili.com/video/BV1TTf5YrESz/").getContent());
}
}

View File

@@ -0,0 +1,135 @@
package com.yutou.qqbot.gpt;
import com.yutou.okhttp.HttpLoggingInterceptor;
import com.yutou.qqbot.data.baidu.Message;
import com.yutou.qqbot.data.gpt.OpenAiBean;
import com.yutou.qqbot.http.GPTApi;
import com.yutou.qqbot.http.GPTBuilder;
import com.yutou.qqbot.utlis.ConfigTools;
import com.yutou.qqbot.utlis.StringUtils;
import lombok.val;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class SiliconGPTManager extends AbsGPTManager {
//生成单例模式
private volatile static SiliconGPTManager instance = new SiliconGPTManager();
private SiliconGPTManager() {
val load = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.GPT_SILICON, String.class);
String defModel = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B";
if (!StringUtils.isEmpty(load)) {
defModel = load;
}
setModel(defModel);
}
public static SiliconGPTManager getInstance() {
if (instance == null) {
synchronized (SiliconGPTManager.class) {
if (instance == null) {
instance = new SiliconGPTManager();
}
}
}
return instance;
}
@Override
public Message sendTmpMessage(String user, String message, String tmpModel) {
return null;
}
@Override
public synchronized Message sendMessage(String user, String message) {
// 获取或创建用户锁
AtomicBoolean lock = userLocks.computeIfAbsent(user, k -> new AtomicBoolean(false));
try {
// 尝试加锁(如果已被锁定则立即返回提示)
if (!lock.compareAndSet(false, true)) {
return Message.create("您有请求正在处理中,请稍后再试", true);
}
val builder = GPTBuilder.create(model);
List<Message> list = getMessageList(user);
list.add(Message.create(message));
for (Message msg : list) {
builder.addMessage(msg.getRole(), msg.getContent());
}
val response = GPTApi.getApi().completions(builder.build()).execute();
if (!response.isSuccessful()) {
return Message.create("API请求失败", true);
}
val body = response.body();
if (body == null || body.getData() == null) {
return Message.create("API请求为空", true);
}
if (body.getRetcode() != 0) {
return Message.create(body.getMsg(), true);
}
val choices = body.getData().getChoices();
if (choices == null || choices.isEmpty()) {
return Message.create("没有对话信息", true);
}
val choice = choices.get(choices.size() - 1);
val bot = Message.create(choice.getMessage().getContent(), true);
list.add(bot);
return bot;
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
lock.set(false);
userLocks.remove(user, lock);
}
}
@Override
public AbsGPTManager setModel(String model) {
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.GPT_SILICON, model);
return super.setModel(model);
}
@Override
public File textToImage(String user, String text) {
return null;
}
@Override
public String imageToText(String user, File file) {
return "";
}
@Override
public String getGPTVersion() {
return model;
}
@Override
public int setMaxMessageCount(int count) {
MAX_MESSAGE.set(count);
return count;
}
public static void main(String[] args) {
String model = "THUDM/glm-4-9b-chat";
val message = AbsGPTManager.getManager(SiliconGPTManager.class)
.setModel(model)
.sendMessage("user", "宫廷玉液酒的下一句是什么?");
System.out.println(message);
System.out.println(AbsGPTManager.getManager(SiliconGPTManager.class)
.setModel(model)
.sendMessage("user", "宫廷玉液酒减去大锤等于多少")
);
}
}

View File

@@ -0,0 +1,26 @@
package com.yutou.qqbot.http;
import com.yutou.okhttp.HttpLoggingInterceptor;
import com.yutou.okhttp.api.BaseApi;
import com.yutou.qqbot.utlis.ConfigTools;
import lombok.val;
import java.util.HashMap;
public class GPTApi extends BaseApi {
public static void setLog(boolean log) {
HttpLoggingInterceptor.setLog(log);
}
public static SiliconGPTApi getApi() {
val api = new GPTApi();
api.setURL("https://api.siliconflow.cn/v1/");
// api.setURL("http://127.0.0.1:8080/");
HashMap<String, String> header = new HashMap<>();
header.put("Authorization", "Bearer sk-dcmhlbhyitcdnjbjfgflhwimahdmygfrcaopzjjcpgsfzmzo");
header.put("Content-Type", "application/json");
api.addHeader(header);
return api.createApi(SiliconGPTApi.class);
}
}

View File

@@ -0,0 +1,127 @@
package com.yutou.qqbot.http;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.val;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Data
class Message {
@JSONField(name = "role")
String role;
@JSONField(name = "content")
String content;
public Message(String role, String content) {
this.role = role;
this.content = content;
}
}
@Data
class GPTRequest {
@JSONField(name = "model")
String model;
@JSONField(name = "messages")
List<Message> messages = new ArrayList<>();
@JSONField(name = "stream")
boolean stream = false;
@JSONField(name = "max_tokens")
int maxTokens;
@JSONField(name = "stop")
List<String> stop = new ArrayList<>(List.of("null"));
@JSONField(name = "temperature")
float temperature ;
@JSONField(name = "top_p")
float topP ;
@JSONField(name = "top_k")
int topK ;
@JSONField(name = "frequency_penalty")
float frequencyPenalty;
}
public class GPTBuilder {
private final GPTRequest request;
private GPTBuilder(String model) {
request = new GPTRequest();
request.model = model;
}
public static GPTBuilder create(String model) {
return new GPTBuilder(model);
}
public GPTBuilder addMessage(String content,boolean isGPT) {
request.messages.add(new Message(isGPT ? "assistant" : "user", content));
return this;
}
public GPTBuilder addMessage(String role, String content) {
request.messages.add(new Message(role, content));
return this;
}
public GPTBuilder setMaxTokens(int maxTokens) {
request.maxTokens = maxTokens;
return this;
}
public GPTBuilder setStream(boolean stream) {
request.stream = stream;
return this;
}
public GPTBuilder setTemperature(float temperature) {
request.temperature = temperature;
return this;
}
public GPTBuilder setTopP(float topP) {
request.topP = topP;
return this;
}
public GPTBuilder setTopK(int topK) {
request.topK = topK;
return this;
}
public GPTBuilder setFrequencyPenalty(float frequencyPenalty) {
request.frequencyPenalty = frequencyPenalty;
return this;
}
// 可以根据需要添加更多配置方法
public JSONObject build() {
val json = JSONObject.parse(JSONObject.toJSONString(request));
// 创建一个迭代器来遍历JSON对象的键
Iterator<String> keys = json.keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
Object value = json.get(key);
// 检查值是否为0或为空字符串
if (value == null || value.equals(0) || (value instanceof String && ((String) value).isEmpty())) {
keys.remove(); // 移除键值对
}
}
return json;
}
}

View File

@@ -0,0 +1,17 @@
package com.yutou.qqbot.http;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.model.MessageBean;
import com.yutou.okhttp.HttpBody;
import com.yutou.qqbot.data.gpt.OpenAiBean;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface SiliconGPTApi {
@POST("/chat/completions")
Call<HttpBody<OpenAiBean>> completions(
@Body
JSONObject message
);
}

View File

@@ -3,7 +3,9 @@ package com.yutou.qqbot.interfaces;
import java.io.File;
public abstract class DownloadInterface {
public void onDownloading(double soFarBytes, double totalBytes){};
public void onDownload(File file){};
public void onError(Exception e){};
public void onDownloadStart(){}
public boolean onDownloading(double soFarBytes, double totalBytes){return true;}
}

View File

@@ -3,4 +3,5 @@ package com.yutou.qqbot.interfaces;
public interface ModelInterface {
boolean isUserPublic();
String[] getUsePowers();
String getModelName();
}

View File

@@ -1,14 +1,13 @@
package com.yutou.qqbot.models.Animal;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.napcat.event.MessageEvent;
import com.yutou.qqbot.Annotations.UseModel;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.utlis.Log;
import com.yutou.qqbot.utlis.RedisTools;
import com.yutou.qqbot.utlis.StringUtils;
import com.yutou.qqbot.utlis.WebClient;
import net.mamoe.mirai.event.events.MessageEvent;
import com.yutou.qqbot.utlis.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@@ -19,6 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@UseModel
public class TurnipProphet extends Model {
public static class TurnipData {
public static final String MODEL = "趋势:";
@@ -43,7 +43,7 @@ public class TurnipProphet extends Model {
}
static int nowTime;
static int nowTime = -1;
@Override
public boolean isUserPublic() {
@@ -57,32 +57,47 @@ public class TurnipProphet extends Model {
};
}
@Override
public String getModelName() {
return "大头菜";
}
Long user, sendQQ;
@Override
public void onMessage(Long qq, MessageEvent event, boolean isGroup) {
super.onMessage(qq, event, isGroup);
user = qq;
sendQQ = qq;
if (isGroup) {
if (!event.isAtMe()) {
return;
}
user = event.getSource().getFromId();
}
int money = -1;
try {
if (isGroup) {
msg = msg.replace("@2476945931", "").trim();
}
money = Integer.parseInt(msg.trim());
} catch (Exception e) {
if (msg.equals(QQFromCommands.TURNIP_PROPHET)) {
showData(event.getSource().getFromId());
showData();
}
return;
}
setData(money, event.getSource().getFromId());
setData(money);
}
private void showData(long qq) {
String redisKey = qq + "_turnip";
private void showData() {
String redisKey = user + "_turnip";
String data = RedisTools.get(redisKey);
if (StringUtils.isEmpty(data)) {
QQBotManager.getInstance().sendMessage(qq, "没有本周数据,无法预测");
QQBotManager.getInstance().sendMessage(sendQQ, getMessage("没有本周数据,无法预测"));
return;
}
JSONObject json = JSONObject.parseObject(data);
JSONObject json = JSON.parseObject(data);
String prices = json.getString("prices");
String pattern = null;
if (json.containsKey("old_pattern")) {
@@ -102,16 +117,16 @@ public class TurnipProphet extends Model {
Map<String, String> map = null;
try {
map = openTurnip(prices, pattern);
sendQQ(map, prices, pattern, qq);
sendQQ(map, prices, pattern);
} catch (Exception e) {
e.printStackTrace();
showData(qq);
showData();
}
}
private void setData(int money, long qq) {
String redisKey = qq + "_turnip";
private void setData(int money) {
String redisKey = user + "_turnip";
String data = RedisTools.get(redisKey);
String pattern = null;
JSONObject json;
@@ -119,6 +134,9 @@ public class TurnipProphet extends Model {
if (StringUtils.isEmpty(data) || getDay() == 0) {
array = new JSONArray();
json = new JSONObject();
if (getDay() == 0 && !StringUtils.isEmpty(data)) {
json = JSON.parseObject(data);
}
array.add(-1);
array.add(-1);
array.add(-1);
@@ -133,11 +151,11 @@ public class TurnipProphet extends Model {
array.add(-1);
array.add(-1);
} else {
json = JSONObject.parseObject(data);
json = JSON.parseObject(data);
array = json.getJSONArray("turnip");
}
if (array.getInteger(0) == -1 && getDay() != 0) {
QQBotManager.getInstance().sendMessage(qq, "没有周日买入信息,本周不收录 :(");
QQBotManager.getInstance().sendMessage(sendQQ, getMessage("没有周日买入信息,本周不收录 :("));
return;
}
if (json.containsKey("old_pattern")) {
@@ -148,23 +166,23 @@ public class TurnipProphet extends Model {
}
if (getDay() == 0) {
if (json.containsKey("pattern")) {
if (!json.containsKey("tmp_pattern")) {
json.put("old_pattern", json.getString("pattern"));
pattern = json.getString("pattern");
}
if (money >= 90 && money <= 110) {
array.set(0, money);
}
} else {
if (money >= 9 && money <= 660) {
System.out.println("array = " + array);
System.out.println("array.size() = " + array.size());
if (nowTime < 12) {
pattern = json.getString("old_pattern");
}
json.put("tmp_pattern", json.getString("pattern"));
}
array.set(0, money);
} else {
json.remove("tmp_pattern");
if (getTime() < 12) {
array.set(getDay() * 2 - 1, money);
} else {
array.set(getDay() * 2, money);
}
}
}
json.put("turnip", array);
StringBuilder builder = new StringBuilder();
for (Object o : array) {
@@ -186,42 +204,46 @@ public class TurnipProphet extends Model {
case "小幅上涨(四期型)" -> pattern = "3";
}
}
QQBotManager.getInstance().sendMessage(qq, "已记录,正在预测本周走势...");
QQBotManager.getInstance().sendMessage(sendQQ, getMessage("已记录,正在预测本周走势..."));
Map<String, String> map = openTurnip(prices, pattern);
String tmp_pattern = sendQQ(map, prices, pattern, qq);
if (map == null) {
map = openTurnip(prices, pattern);
}
String tmp_pattern = sendQQ(map, prices, pattern);
if (!StringUtils.isEmpty(tmp_pattern)) {
json.put("pattern", tmp_pattern);
}
RedisTools.set(redisKey, json.toJSONString());
} catch (Exception e) {
setData(money, qq);
e.printStackTrace();
setData(money);
}
}
private String sendQQ(Map<String, String> map, String prices, String pattern, long qq) {
if (map == null) {
private String sendQQ(Map<String, String> map, String prices, String pattern) {
String url = String.format("https://turnipprophet.io?prices=%s%s",
prices,
pattern == null ? "" : "&pattern=" + pattern
);
QQBotManager.getInstance().sendMessage(qq, "没有结果,请检查数据是否有误。 \n网页预览" + url);
if (map == null) {
QQBotManager.getInstance().sendMessage(sendQQ, getMessage("没有结果,请检查数据是否有误。 \n网页预览\n" + url));
return null;
}
JSONObject pr = JSONObject.parseObject(map.get(TurnipData.MODEL));
JSONObject pr = JSON.parseObject(map.get(TurnipData.MODEL));
JSONArray prArray = pr.getJSONArray(TurnipData.MODEL);
StringBuilder out = new StringBuilder();
out.append("预测结果如下:\n");
out.append(TurnipData.MODEL).append(prArray.getJSONObject(0).getString(TurnipData.MODEL)).append("\n");
out.append(TurnipData.PR).append(prArray.getJSONObject(0).getString(TurnipData.PR)).append("\n");
out.append("购入价:").append(prices.split("\\.")[0]).append("\n");
if (getDay() == 0) {
out.append("满背包(4行)购入价:").append(4000 * Integer.parseInt(prices.split("\\.")[0])).append("\n");
}
out.append(TurnipData.MIX).append(map.get(TurnipData.MIX)).append("\n")
.append(TurnipData.MAX).append(map.get(TurnipData.MAX)).append("\n")
.append(TurnipData.DAY).append(map.get(TurnipData.DAY)).append("\n")
@@ -247,32 +269,49 @@ public class TurnipProphet extends Model {
out.append(tmp.getString(TurnipData.MODEL)).append(":").append(tmp.getString(TurnipData.PR)).append("\n");
}
out.append("------------").append("\n");
out.append("网页版:").append("\n").append(url).append("\n");
out.append("祝好运 :)");
Log.i("TurnipProphet", out.toString());
QQBotManager.getInstance().sendMessage(qq, out.toString());
if (ConfigTools.load(ConfigTools.CONFIG, ConfigTools.TURNIP_PROPHET_SEND_TMP_GROUP, Boolean.class)) {
out.append("\n使用者:").append(sendQQ);
sendQQ = 891655174L;
}
Log.i("TurnipProphet", out.toString() + "\n 发送QQ" + sendQQ);
QQBotManager.getInstance().sendMessage(sendQQ, getMessage(out.toString()));
return prArray.getJSONObject(0).getString(TurnipData.MODEL);
}
@Override
public void onTime(String time) {
super.onTime(time);
public void onTime(Long qq, String time) {
super.onTime(qq, time);
nowTime = Integer.parseInt(time.split(":")[0]);
}
public int getTime() {
if (nowTime == -1) {
nowTime = Integer.parseInt(AppTools.getHours());
}
return nowTime;
}
private int getDay() {
return Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1;
}
public static void main(String[] args) throws Exception {
TurnipProphet prophet = new TurnipProphet();
prophet.setData(88, 583819556);
String prices = "108.93.89.84.79........";
String pattern = "0";
Map<String, String> map = prophet.openTurnip(prices, pattern);
prophet.sendQQ(map, prices, pattern);
}
public Map<String, String> openTurnip(String prices, String pattern) throws Exception {
String url = String.format("https://turnipprophet.io?prices=%s%s",
String url = String.format("http://%s/?prices=%s%s",
ConfigTools.load(ConfigTools.CONFIG, ConfigTools.TURNIP_PROPHET_SERVER, String.class),
prices,
pattern == null ? "" : "&pattern=" + pattern
);
@@ -284,10 +323,13 @@ public class TurnipProphet extends Model {
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Thread.sleep(500);
WebElement element = driver.findElement(By.id("output"));
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
List<WebElement> list = element.findElements(By.tagName("tr"));
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
JSONObject pr = new JSONObject();
JSONArray array = new JSONArray();
if (list.size() == 0) {
WebClient.getInstance().quit();
return null;
}
@@ -324,18 +366,27 @@ public class TurnipProphet extends Model {
}
}
}
int maxMoney = 0;
String maxDay = null;
for (String key : map.keySet()) {
System.err.println("记录最高日:" + map.get(key) + " > " + key);
if (!key.equals(TurnipProphet.TurnipData.MAX) &&
map.get(key).contains(map.get(TurnipProphet.TurnipData.MAX))) {
map.put(TurnipProphet.TurnipData.DAY, key);
break;
if (map.get(key).contains("~")) {
for (String s : map.get(key).split("~")) {
if (Integer.parseInt(s) > maxMoney) {
maxMoney = Integer.parseInt(s);
maxDay = key;
}
}
} else {
if (Integer.parseInt(map.get(key)) > maxMoney) {
maxMoney = Integer.parseInt(map.get(key));
maxDay = key;
}
}
}
map.put(TurnipProphet.TurnipData.DAY, maxDay);
pr.put(TurnipProphet.TurnipData.MODEL, array);
map.put(TurnipProphet.TurnipData.MODEL, pr.toJSONString());
driver.close();
driver.quit();
WebClient.getInstance().quit();
return map;
}
}

View File

@@ -0,0 +1,139 @@
package com.yutou.qqbot.models.BiliBili;
import com.yutou.napcat.event.MessageEvent;
import com.yutou.qqbot.Annotations.UseModel;
import com.yutou.qqbot.QQBotManager;
import com.yutou.qqbot.bilibili.BiliBiliUtils;
import com.yutou.qqbot.bilibili.BiliLogin;
import com.yutou.qqbot.models.Model;
import com.yutou.qqbot.utlis.RedisTools;
import java.util.Set;
@UseModel
public class BiliBiliLive extends Model {
@Override
public boolean isUserPublic() {
return false;
}
@Override
public String[] getUsePowers() {
return new String[]{
Model.QQGroupCommands.BILI_LIVE_DANMU_LIST,
Model.QQGroupCommands.BILI_LIVE_DANMU_SEND,
QQGroupCommands.BILI_LIVE_DANMU_DEL
};
}
@Override
public String getModelName() {
return "BiliBili Live Sign in";
}
@Override
public synchronized void onTime(Long qq, String time) {
super.onTime(qq, time);
if ("07:01:00".equals(time)) {
if (!new BiliLogin(QQBotManager.defQQ).testLogin()) {
new BiliLogin(QQBotManager.defQQ).loginAsQQ();
System.out.println(BiliBiliUtils.getInstance(QQBotManager.defQQ).getLoginInfo());
return;
}
signLive(QQBotManager.defQQ, qq);
}
}
private void signLive(long qq, long sendQQ) {
if (!new BiliLogin(qq).testLogin()) {
new BiliLogin(qq).loginAsQQ();
return;
}
BiliBiliUtils biliUtils = BiliBiliUtils.getInstance(qq);
QQBotManager.getInstance().sendMessage(sendQQ, biliUtils.liveSignIn());
Set<String> biliLive = RedisTools.list_get("bili_live");
StringBuilder builder = new StringBuilder();
for (String id : biliLive) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
boolean sign = biliUtils.sendLiveDanmu(Integer.parseInt(id), "打卡");
builder.append("BiliLiveSign").append(id).append(":").append(sign).append("\n");
}
QQBotManager.getInstance().sendMessage(sendQQ, builder.toString());
/* BiliBiliAppUtils appUtils = new BiliBiliAppUtils(QQBotManager.defQQ);
AppUserTask oldTask = appUtils.startAppTask();
AppUserTask newTask = appUtils.getTaskProgress();
builder = new StringBuilder();
builder.append("执行APP任务").append("\n").append(AppUserTask.toMessageFormat(oldTask, newTask));
QQBotManager.getInstance().sendMessage(sendQQ, builder.toString());*/
}
@Override
public void onMessage(Long qq, MessageEvent event, boolean isGroup) {
super.onMessage(qq, event, isGroup);
if (!msg.startsWith(QQGroupCommands.BILI_LIVE_DANMU_SEND) &&
!msg.startsWith(QQGroupCommands.BILI_LIVE_DANMU_DEL) &&
!msg.startsWith(QQGroupCommands.BILI_LIVE_DANMU_LIST)) {
return;
}
if (msg.equals(QQGroupCommands.BILI_LIVE_DANMU_SEND)) {
signLive(user, qq);
return;
}
BiliBiliUtils biliUtils = BiliBiliUtils.getInstance(isGroup ? event.getSource().getFromId() : qq);
StringBuilder message;
message = new StringBuilder();
try {
boolean isDel = false;
if (msg.startsWith(QQGroupCommands.BILI_LIVE_DANMU_DEL)) {
isDel = true;
msg = msg.replace(QQGroupCommands.BILI_LIVE_DANMU_DEL, "").trim();
} else if (msg.startsWith(QQGroupCommands.BILI_LIVE_DANMU_SEND)) {
msg = msg.replace(QQGroupCommands.BILI_LIVE_DANMU_SEND, "").trim();
} else {
msg = "0";
}
Integer roomId = Integer.parseInt(msg);
if (!new BiliLogin(qq).testLogin()) {
new BiliLogin(qq).loginAsQQ();
return;
}
if (biliUtils.checkLiveRoom(roomId) && roomId != 0) {
if (isDel && RedisTools.list_isExist("bili_live", roomId + "")) {
RedisTools.list_remove("bili_live", roomId + "");
message.append("直播签到删除成功").append("\n");
} else if (!RedisTools.list_isExist("bili_live", roomId + "")) {
RedisTools.list_add("bili_live", roomId + "");
message.append("直播签到添加成功").append("\n");
}
} else if (roomId != 0) {
message.append("直播签到操作失败\n");
}
} catch (Exception e) {
message = new StringBuilder("直播签到添加失败\n");
}
message.append("-----直播签到房间号-----\n");
Set<String> biliLive = RedisTools.list_get("bili_live");
for (String id : biliLive) {
message.append(id)
.append(":")
.append(biliUtils.getUserInfo(
biliUtils.getLiveRoom(Integer.parseInt(id))
.getJSONObject("data")
.getInteger("uid"))
.getJSONObject("data")
.getString("name"))
.append("\n");
}
QQBotManager.getInstance().sendMessage(qq, message.toString());
}
public static void main(String[] args) {
new BiliBiliLive().signLive(QQBotManager.defQQ, 0);
}
}

Some files were not shown because too many files have changed in this diff Show More