hundun000 / petpet

Mirai 摸摸头插件的原生java实现

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Petpet

Mirai version GitHub GitHub all releases GitHub Repo stars GitHub release (latest by date) GitHub issues GitHub closed issues GitHub closed pull requests

自定义合成图片的 Mirai 插件 / 独立程序, 灵感/部分数据来自 nonebot-plugin-petpet

原生 java 编写, kotlin仅用于数据序列化, 使用底层API, 多线程优化: 轻量, 高性能, 易拓展

在线编辑器

使用方法

  1. 下载 最新版本

  2. 将插件放入 Mirai/plugins/

  3. 下载 图片素材

  4. 将图片素材放入 Mirai/data/xmmt.dituon.petpet

  5. 使用 戳一戳30% 的概率触发; 或发送 pet @xxx

pet key @xxxkey @xxx 可返回指定图片 例如 pet kiss @xxx kiss @xxx

可通过发送的图片生成Petpet kiss [图片], 支持GIF

可通过回复构造图片, 例如 [图片] -> [回复[图片]] 对称

可使用 pet指令 获取 keyList

以上配置 均可在配置文件中修改

配置文件

首次运行 Petpet 插件时,会生成 Mirai/config/xmmt.dituon.petpet/Petpet.yml 文件

配置项说明

展开/收起
  • command: pet

触发petpet指令, 默认为pet

例: pet @xxx pet kiss @xxx

仅发送pet时会返回keyList


  • probability: 30

戳一戳 触发概率, 0-100整数, 默认为 30%


  • antialias: true

画布抗锯齿, 默认为true


  • disabled: []

禁用表列, 默认为空, 在此数组中的key不会被随机触发 (会覆盖data.json中的配置)


  • keyCommandHead: ''

key作为指令头时的前缀, 默认为空

例 (配置项为'#'时): #kiss @xxx osu hso!


  • respondReply: true

响应回复的消息, 默认为true

可通过回复消息 定位到之前发送的图片并构造petpet

启用后 会缓存接收到的图片(见cachePoolSize)

例 : [回复[图片]]kiss(等价于 kiss [图片])


  • cachePoolSize: 10000

respondReply=true时, 图片消息缓存池大小, 默认为10000

本质为HashMap<imageId(long), imageUrl(String)>, 超过此限制会清空Map


  • respondSelfNudge: false

某些情况下, 机器人会主动戳其他成员, 响应机器人自己发出的戳一戳, 默认为false


  • keyListFormat: FORWARD

发送petkeyList响应格式, 默认为FORWARD

枚举: MESSAGE(发送普通消息) FORWARD(发送转发消息) IMAGE(发送图片)


  • disablePolicy: FULL

发送pet on/off时 禁用哪些功能, 默认为FULL

枚举: NONE(无效) NUDGE(只禁用戳一戳) MESSAGE(只禁用指令) FULL(同时禁用戳一戳和指令)

  • fuzzy: false

模糊匹配用户名, 默认为false

例 : (配置项为true时): kiss @田所浩二(响应) kiss 浩二(响应)


  • strictCommand: true

严格匹配指令, 默认为true

人话: 可以省略key后的空格

例 : (配置项为false时): kiss 田所(响应) kiss田所(响应)


  • synchronized: false

消息事件同步锁, 会锁住相同的消息事件, 默认为false

人话: 多机器人对于同一条指令只有一个会响应


  • gifEncoder: ANIMATED_LIB

GIF编码器, 默认为ANIMATED_LIB

枚举: BUFFERED_STREAM: 基于缓存的STREAM流, 在编码过程中对Gif进行压缩;

  • 编码速度较慢, 所需堆内存小, 生成Gif体积小

ANIMATED_LIB: 基于byte[]序列, 使用多线程分析像素;

  • 编码速度极快, 所需堆内存较多, 生成Gif体积较小

SQUAREUP_LIB: 基于int[][]数组, 编码时不使用awt库, Gif压缩比低;

  • 编码速度极慢, 所需堆内存多, 生成Gif体积较大

  • gifMaxSize: []

GIF缩放阈值/尺寸, 默认为空 (不限制)

[width, height, frameLength]:

当Gif长度超过frameLength时, 会对Gif进行等比例缩放

注: 缩放在图片合成时进行, 不会影响性能

例: (配置项为-200 -200 -32]时)

  • 当Gif长度超过32帧时, 检查Gif尺寸
  • 当Gif尺寸大于200*200时, 对Gif进行等比例缩放
  • Gif缩放后 最长边不会超过设定值 (当Gif中包含40帧, 尺寸为300*500时)
  • 输出的Gif长度不变, 尺寸为120*200
  • gifQuality: 10

Gif编码质量(1-99), 默认为10

数字越小, 速度越慢, 质量越好 (大于20时, 速度不会有明显提升)

仅适用于ANIMATED_LIB编码器

  • headless: true

启用headless模式, 默认为true

人话: 有些服务器没有输入输出设备, 画图库无法正常运行, 启用这个配置项可以修复, 因为总是有人不看常见问题, 干脆默认启用了(


  • autoUpdate: true

自动更新PetData, 每次启动时都会检查并自动下载船新pet, 默认为true

注: 仅更新PetData, 不会更新插件版本, 请放心食用

人话: 每次启动都会自动下载新的超赞梗图, 墙裂推荐


  • repositoryUrl: 'https://dituon.github.io/petpet'

仓库地址, 用于自动更新, 默认为此仓库的github page

  • devMode: false

开发模式, 启用后任何人都能使用pet reload指令热重载PetData, 默认为false


  • coolDown: 10

成功触发指令后对该用户的冷却时间(单位为秒), 默认为 1

设置为 -1 可禁用冷却


  • groupCoolDown: -1

成功触发指令后对该群聊的冷却时间, 默认为 1


  • inCoolDownMessage: 技能冷却中...

在冷却时间中触发命令的回复消息

配置项为[nudge]时, 会以戳一戳形式回复


修改后重启 Mirai 以重新加载

权限管理

群主或管理员使用 pet on pet off 以 启用/禁用 戳一戳

pet on/off指令控制的事件可在配置文件中更改

可在配置文件中禁用指定key, 被禁用的key不会随机触发, 但仍可以通过指令使用

图片预览

图片按key排序(见data/xmmt.dituon.petpet/)

展开/收起
key 预览
acclaim
喝彩 欢呼
acclaim
bible
圣经 典中典
bible
breakdown
惊吓 击穿
breakdown
carte
佩可莉姆 菜单 单页
carte
hold_sign
唐可可 举牌 应援
hold_sign
kurumi
胡桃 放大
kurumi
monad
唐可可 拍 单页
monad
point_tv
康纳 电视
point_tv
remake
泥头车 创 重开
remake
reward
伊蕾娜 赏金 报酬
reward
watch_tv
汤姆 电视
watch_tv
certificate
喜报
certificate
anyasuki
阿尼亚 喜欢
anyasuki
bite
啃 咬
bite
breast
胸 凶
breast
cast
cast
center_symmetry
中心对称 左上对称
center_symmetry
coupon
陪睡
coupon
cover_face
cover_face
crawl
crawl
decent_kiss
抱歉
decent_kiss
distracted
注意力
distracted
dont_touch
不要靠近
dont_touch
down_symmetry
对称 下对称 上下对称
down_symmetry
eat
eat
fencing
击剑 🤺
fencing
garbage
垃圾桶 垃圾 探头
garbage
hammer
hammer
interview
采访
interview
jiujiu
么么
jiujiu
keep_away
远离
keep_away
kiss
亲 热吻
kiss
knock
敲 打
knock
left_down_symmetry
中心对称 左下对称
left_down_symmetry
leg
leg
like
永远喜欢
like
loading
加载 加载中
loading
make_friend
加好友
make_friend
marry
结婚
marry
nano
纳米科技
nano
need
需要
need
osu osu
painter
painter
pat
pat
perfect
完美
perfect
petpet
摸 摸头
petpet
play
玩 顶
play
police
警察
police
pound
pound
pr
舔屏
pr
punch
打拳
punch
record
唱片
record
right_down_symmetry
中心对称 右下对称
right_down_symmetry
right_symmetry
对称 右对称 左右对称
right_symmetry
right_up_symmetry
中心对称 右上对称
right_up_symmetry
roll
滚 推
roll
rub
舔 prpr
rub
safe_sense
安全感
safe_sense
suck
suck
support
精神支柱
support
symmetry
对称 左对称 左右对称
symmetry
tear
tear
thinkwhat
thinkwhat
throw
throw
thump
thump
tightly
tightly
twist
twist
up_symmetry
对称 上对称 上下对称
up_symmetry
wallpaper
瑞克 壁纸
wallpaper
worship
膜拜
worship
yoasobi
群青
yoasobi

..more&more

自定义

在线编辑器

data.json

./data/xmmt.dituon.petpet/ 下的目录名为 key ,插件启动时会遍历 ./data/xmmt.dituon.petpet/$key/data.json

data.json 标准如下 (以 thump/data.json 为例)

// *为必须参数
{
  "type": "GIF", // 图片类型(enum)*
  "avatar": [{ // 头像(avatarObj[])*, 详见下文
      "type": "TO",
      "pos": [
        [65, 128, 77, 72], [67, 128, 73, 72], [54, 139, 94, 61], [57, 135, 86, 65]
      ],
      "round": true,
      "avatarOnTop": false
    }],
  "text": [], // 文字(textObj[])*, 详见下文
  "inRandomList": false, // 在随机列表中(bolean)
  "reverse": false, // GIF倒放(bolean)
  "delay": 50, // 帧间延时(ms/int), 默认为65
  "background": {}, // 背景(obj), 详见下文
  "alias": [ "别名1", "别名2" ], // 别名(str[])
  "hidden": false // 隐藏(bolean)
}

部分配置项设计参考了CSS标准, 并尽可能实现CSS渲染效果

图片类型枚举

type

  • GIF 动图
  • IMG 静态图片

坐标

坐标的基本组成单位是 4长度 int[] 数组

其中,前两项为 左上角顶点坐标, 后两项为 宽度和高度

例: [65, 128, 77, 72] 即 头像的左上角顶点坐标是 (65,128), 宽度为 77, 高度为 72

如果是 GIF 类型,坐标应为二维数组,GIF 的每一帧视为单个图像文件

"pos": [ // pos的元素对应GIF的4帧
    [65, 128, 77, 72], [67, 128, 73, 72], [54, 139, 94, 61], [57, 135, 86, 65]
  ],

如果是IMG类型, 可以使用一维数组

  "pos": [0, 0, 200, 200]

4.0版本后, 坐标支持变量运算, 例如 [100,100,"width/2","height*1.5^2"]

仿射变换/图像变形

坐标格式枚举posType

  • ZOOM 缩放(见上文)
  • DEFORM 变形

DEFORM 坐标格式为 [[x1,y1],[x2,y2],[x3,y3],[x4,y4],[x_anchor,y_anchor]]; 分别对应图片的[[左上角],[左下角],[右下角],[右上角],[锚点]],四角坐标用相对于锚点的偏移量表示

目前仿射变换仅支持单帧

头像

3.0版本后 提供了更灵活的头像构造方法, 与之前的版本有很大差别

"avatar": [
    {
      "type": "FROM", //头像类型枚举(enum), 非空
      "pos": [[92, 64, 40, 40], [135, 40, 40, 40], [84, 105, 40, 40]], // 坐标
      "round": true, // 值为true时, 头像裁切为圆形, 默认为false
      "avatarOnTop": true, // 值为true时, 头像图层在背景之上, 默认为true
      "angle": 90, // 初始角度
      "opacity": 0.5 // 不透明度
    },
    {
      "type": "TO", 
      "pos": [[5, 8], [60, 90], [50, 90], [50, 0], [60, 120]],
      "posType": "DEFORM", // 图像变形 坐标格式, 默认为ZOOM
      "antialias": true, // 抗锯齿, 对头像单独使用抗锯齿算法, 默认为false
      "rotate": false // 值为true时, GIF类型的头像会旋转, 默认为false
    },
    {
      "type": "GROUP", 
      "pos": [[182, 64, "width/2", "height*1.5^2"], [225, 40, "40", 40], [174, 105, 40, "height+width"]], // 支持变量运算
      "crop": [0, 0, 50, 100], // 图片裁切坐标[x1, y1, x2, y2], 可简写为 [50, 100]
      "cropType": "PERCENT", // 裁切格式, 默认为NONE
      "style": [ // 风格化
        "MIRROR",
        "GRAY"
      ],
      "fit": "CONTAIN" // 填充模式, 默认为 FILL
    }
  ]

IMG中, 当rotate = true时, 头像会随机旋转角度, angle为最大值(angle = 0时, 随机范围为0-359)

头像类型枚举 type

  • FROM 发送者头像
  • TO 接收者头像, 或构造的图片
  • GROUP 群头像
  • BOT 机器人头像
  • RANDOM 随机头像 (随机从群聊成员中选择, 不会重复)

裁切格式枚举 cropType

  • NONE 不裁切
  • PIXEL 按像素裁切
  • PERCENT 按百分比裁切

风格化枚举 style

  • MIRROR 水平镜像
  • FLIP 上下翻转
  • GRAY 灰度化
  • BINARIZATION 二值化

填充模式 fit

  • CONTAIN 缩小以适应画布, 不改变原比例
  • COVER 裁切以适应画布, 不改变原比例
  • FILL 拉伸, 改变原比例

坐标变量

  • width 原图宽度
  • height 原图高度

文字

如果你想在图片上添加文字,可以编辑 text

"text": [ // 这是一个数组, 可以添加很多文字
    {
      "text": "Petpet!", // 文字内容
      "color": "#66ccff", // 颜色, 默认为#191919
      "pos": [100, 100], // 坐标, 默认为 [2,14]
      "size": 24 // 字号, 默认为12
    },
    {
      "text": "发送者: $from, 接收者: $to", // 支持变量
      "color": [0,0,0,255], // 颜色可以使用RGB或RGBA的格式
      "pos": [20, 150], // 坐标
      "position": ["CENTER", "BOTTOM"], //坐标计算基准([x, y])
      "font": "宋体", // 字体, 默认为黑体
      "strokeColor": "#ffffff", // 描边颜色
      "strokeSize": 2 // 描边宽度
    },
    {
      "text": "$txt1[我]超市$txt2[你]!", // 支持关键词变量
      "pos": [0,200,300], // 第三个值为文本最大宽度
      "align": "CENTER", // 对齐方式, 默认为LEFT
      "wrap": "ZOOM", // 显示设置, 默认为NONE
      "style": "BLOD", // 字体样式, 默认为PLAIN
      "greedy": true // 贪婪匹配模式, 会匹配多余的关键词
    }
  ]

变量

  • $from : 发送者, 会被替换为发送者群名片,如果没有群名片就替换为昵称
  • $to : 接收者, 被戳或At的对象, 发送图片构造时为"你"
  • $group : 群名称
  • $txt(i)[(xxx)] : 文本变量, 可用于生成meme图, i为关键词索引, xxx为默认值; 例: $txt1[我]超市$txt2[你] 指令为 pet [key] 我 你

需要更多变量请提交 Issue

font

data/fonts目录下的字体文件会注册到环境中

align

  • LEFT: 左对齐
  • RIGHT: 右对齐
  • CENTER: 居中对齐

wrap

  • NONE: 不换行
  • BREAK: 自动换行
  • ZOOM: 自动缩放

使用BREAKZOOM时, maxWidth 默认为200

style

  • PLAIN: 默认
  • BLOD: 粗体
  • ITALIC: 斜体

position

  • LEFT: 左定位(默认)
  • RIGHT: 右定位
  • TOP: 上定位(默认)
  • BOTTOM: 下定位
  • CENTER: 居中定位

background

4.0版本后, 支持动态创建画布

"background": {
    "size": ["avatar0Width*2","avatar0Height"], //支持变量运算
    "color": "#f0f0f0" //支持hex或rgba数组
  }

坐标变量

  • avatar(i)Width i号头像(i为定义头像时的顺序, 从0开始)处理后的宽度
  • avatar(i)Height i号头像处理后的高度
  • text(i)Width i号文本渲染后的宽度
  • text(i)Height i号文本渲染后的高度

WebServer

除了作为Mirai插件, Petpet 也可以作为http服务器单独运行, 可被其它项目/语言使用

java -jar petpet.jar

启动时会生成 config.json:

{
  "port": 2333, // 监听端口
  "webServerThreadPoolSize": 10, // HTTP服务器线程池容量
  "dataPath": "data/xmmt.dituon.petpet", // PetData路径
  "gifMaxSize": [200, 200, 32], // GIF缩放阈值, 详见上文
  "gifEncoder": "ANIMATED_LIB", // GIF编码器, 详见上文
  "gifQuality": 100, // GIF质量, 详见上文
  "gifMakerThreadPoolSize": 0, // GIF编码器线程池容量, 详见上文
  "headless": true // 使用headless模式
}

程序使用com.sun.net.httpserver实现http服务器

PetServer API

访问 127.0.0.1:2333/petpet 以获取 PetDataList

GET

使用 GET 传递参数, 例如 127.0.0.1:2333/petpet?key=petpet&toAvatar=$avatarUrl 127.0.0.1:2333/petpet?key=osu&textList=hso!

结构

展开/收起
  • key (str): 对应PetData,例如kiss rub
  • fromAvatar toAvatar groupAvatar botAvatar (url): 头像URL地址, encodeURIComponent(rawUrl)
  • randomAvatarList (url[]): 随机头像列表, 使用,分割多个url
  • fromName toName groupName (str): 昵称, 有默认值
  • textList (str): 根据空格分割此字符串, 作为额外数据
POST

使用 POST 传递参数, 例如 127.0.0.1:2333/petpet

{
    "key": "petpet",
    "to": {
        "name":"d2n",
        "avatar":"https://q1.qlogo.cn/g?b=qq&nk=2544193782&s=640"
    },
    "randomAvatarList": [
        "url"
    ],
    "textList": [
        "test"
    ]
}

可参考example-script中的代码实现请求

语言 示例
javascript post.js get.js
python example.py
php example.php

常见问题

  • 戳一戳无法触发?

    检查 Mirai 登录协议, 仅 ANDORID_PHONE 可以收到 戳一戳 消息

  • 没有生成配置文件?

    Mirai 2.11.0 提供了新的 JavaAutoSaveConfig 方法, 请更新Mirai版本至 2.11.0 (不是2.11.0-M1), 旧版本不支持自定义配置项

  • Exception in coroutine <unnamed>?

    图片素材应位于 Mirai/data/xmmt.dituon.petpet 目录下, 请检查路径

  • Could not initialize class java.awt.Toolkit?

    对于无输入输出设备的服务器 需要启用headless

  • 自动更新下载速度慢 / 无法连接远程资源?

    修改Petpet.ymlrepositoryUrl的值为'https://ghproxy.com/https://raw.githubusercontent.com/Dituon/petpet/main'(高速镜像)

  • 自动更新后 读取data.json出错?

    自动更新时网络出错导致, 删除出错的文件 重新获取即可

  • 其它错误? 问题?

    若此文档无法解决您的问题, 欢迎提交issue

性能 & 兼容性

程序使用底层java.awt类合成图片, 渲染时使用多线程, 静态图片渲染时间一般不会超过1ms

对GIF编码器的分析, 转换, 映射部分进行多线程优化, 速度极快

Android JVM没有实现java.awt, 推荐使用JDK 11+版本

分享你的作品 (模板)

如果你想分享自定义的 Petpet, 欢迎Pr

二次开发

程序提供超多实用API 拓展性极强, 附有互动式开发实例, 欢迎初学者学习!

后话

如果此插件和您预期的一样正常工作,请给我一个 star

欢迎提交任何请求

交流群: 828350277

About

Mirai 摸摸头插件的原生java实现

License:GNU Affero General Public License v3.0


Languages

Language:Java 73.7%Language:JavaScript 17.9%Language:Kotlin 4.9%Language:CSS 1.4%Language:PHP 0.9%Language:HTML 0.6%Language:Python 0.5%