wechaty-web-panel 0.2.16 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/workspace.xml +34 -8
- package/CHANGELOG.md +16 -0
- package/README.md +17 -10
- package/package.json +11 -15
- package/src/common/index.js +15 -10
- package/src/handlers/on-login.js +3 -3
- package/src/handlers/on-message.js +1 -1
- package/src/lib/index.js +5 -225
- package/src/proxy/api.js +13 -37
- package/src/proxy/mqtt.js +1 -1
- package/src/puppeteer-paint/drawHelp.js +237 -0
- package/src/puppeteer-paint/index.js +37 -0
- package/src/puppeteer-paint/lanuch.js +38 -0
- package/src/puppeteer-paint/mainConfig.js +8 -0
- package/src/service/event-dispatch-service.js +6 -6
- package/src/service/msg-filters.js +2 -1
- package/src/service/room-async-service.js +52 -8
package/.idea/workspace.xml
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<project version="4">
|
|
3
3
|
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="2e980355-75b9-47a9-b344-f25eda9493b2" name="Default Changelist" comment="feat(模块): 添加了个很棒的功能 fix(模块): 修复了一些 bug docs(模块): 更新了一下文档 UI(模块): 修改了一下样式 chore(模块): 对脚手架做了些更改 locale(模块): 为国际化做了微小的贡献"
|
|
5
|
-
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
|
|
6
|
-
<change beforePath="$PROJECT_DIR$/src/proxy/api.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/proxy/api.js" afterDir="false" />
|
|
7
|
-
</list>
|
|
4
|
+
<list default="true" id="2e980355-75b9-47a9-b344-f25eda9493b2" name="Default Changelist" comment="feat(模块): 添加了个很棒的功能 fix(模块): 修复了一些 bug docs(模块): 更新了一下文档 UI(模块): 修改了一下样式 chore(模块): 对脚手架做了些更改 locale(模块): 为国际化做了微小的贡献" />
|
|
8
5
|
<option name="SHOW_DIALOG" value="false" />
|
|
9
6
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
10
7
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
@@ -36,7 +33,7 @@
|
|
|
36
33
|
</component>
|
|
37
34
|
<component name="PropertiesComponent">
|
|
38
35
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
39
|
-
<property name="last_opened_file_path" value="$PROJECT_DIR$/
|
|
36
|
+
<property name="last_opened_file_path" value="$PROJECT_DIR$/src/puppeteer-paint" />
|
|
40
37
|
<property name="node.js.detected.package.eslint" value="true" />
|
|
41
38
|
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
|
42
39
|
<property name="nodejs_package_manager_path" value="npm" />
|
|
@@ -47,11 +44,11 @@
|
|
|
47
44
|
</component>
|
|
48
45
|
<component name="RecentsManager">
|
|
49
46
|
<key name="CopyFile.RECENT_KEYS">
|
|
50
|
-
<recent name="$PROJECT_DIR$/
|
|
47
|
+
<recent name="$PROJECT_DIR$/src/puppeteer-paint" />
|
|
51
48
|
<recent name="$PROJECT_DIR$" />
|
|
49
|
+
<recent name="$PROJECT_DIR$/test" />
|
|
52
50
|
<recent name="$PROJECT_DIR$/koa/bash" />
|
|
53
51
|
<recent name="$PROJECT_DIR$/koa/pubilc/static" />
|
|
54
|
-
<recent name="$PROJECT_DIR$/koa/pubilc/static/img" />
|
|
55
52
|
</key>
|
|
56
53
|
</component>
|
|
57
54
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
|
|
@@ -78,7 +75,32 @@
|
|
|
78
75
|
<workItem from="1634271782737" duration="2406000" />
|
|
79
76
|
<workItem from="1634278985825" duration="1179000" />
|
|
80
77
|
<workItem from="1634544457610" duration="4850000" />
|
|
81
|
-
<workItem from="1634642615016" duration="
|
|
78
|
+
<workItem from="1634642615016" duration="19868000" />
|
|
79
|
+
<workItem from="1634781971524" duration="5097000" />
|
|
80
|
+
<workItem from="1636020036226" duration="4142000" />
|
|
81
|
+
<workItem from="1636700616248" duration="611000" />
|
|
82
|
+
<workItem from="1637723811654" duration="126000" />
|
|
83
|
+
<workItem from="1638588076329" duration="34000" />
|
|
84
|
+
<workItem from="1639099930278" duration="1299000" />
|
|
85
|
+
<workItem from="1639129806549" duration="77000" />
|
|
86
|
+
<workItem from="1639464210268" duration="219000" />
|
|
87
|
+
<workItem from="1639473278118" duration="72000" />
|
|
88
|
+
<workItem from="1639486141688" duration="66000" />
|
|
89
|
+
<workItem from="1639539045086" duration="75000" />
|
|
90
|
+
<workItem from="1639712956341" duration="178000" />
|
|
91
|
+
<workItem from="1640929149202" duration="6000" />
|
|
92
|
+
<workItem from="1641278400321" duration="13000" />
|
|
93
|
+
<workItem from="1641442984815" duration="5000" />
|
|
94
|
+
<workItem from="1642212984216" duration="11645000" />
|
|
95
|
+
<workItem from="1642384832300" duration="994000" />
|
|
96
|
+
<workItem from="1642386021423" duration="4268000" />
|
|
97
|
+
<workItem from="1642647009185" duration="3937000" />
|
|
98
|
+
<workItem from="1642657426395" duration="780000" />
|
|
99
|
+
<workItem from="1642678719784" duration="603000" />
|
|
100
|
+
<workItem from="1643094529038" duration="490000" />
|
|
101
|
+
<workItem from="1644319873832" duration="1868000" />
|
|
102
|
+
<workItem from="1645362804718" duration="427000" />
|
|
103
|
+
<workItem from="1645411323461" duration="14144000" />
|
|
82
104
|
</task>
|
|
83
105
|
<servers />
|
|
84
106
|
</component>
|
|
@@ -97,4 +119,8 @@
|
|
|
97
119
|
</option>
|
|
98
120
|
<option name="oldMeFiltersMigrated" value="true" />
|
|
99
121
|
</component>
|
|
122
|
+
<component name="XSLT-Support.FileAssociations.UIState">
|
|
123
|
+
<expand />
|
|
124
|
+
<select />
|
|
125
|
+
</component>
|
|
100
126
|
</project>
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
## 更新日志
|
|
2
2
|
|
|
3
|
+
### V1.0.2(2022-02-21)
|
|
4
|
+
|
|
5
|
+
1、去除canvas依赖,使用puppeteer生成图片
|
|
6
|
+
|
|
7
|
+
### V1.0.1(2022-02-08)
|
|
8
|
+
|
|
9
|
+
1、修复参数取值问题
|
|
10
|
+
|
|
11
|
+
### V1.0.1(2022-01-20)
|
|
12
|
+
|
|
13
|
+
1、升级Wechaty版本到1.x版本,优化部分功能,保持多协议展示形式
|
|
14
|
+
|
|
15
|
+
### V0.2.17(2021-10-22)
|
|
16
|
+
|
|
17
|
+
1、修复群和好友同步问题
|
|
18
|
+
|
|
3
19
|
### V0.2.16(2021-10-20)
|
|
4
20
|
|
|
5
21
|
1、更新疫情的返回数据格式
|
package/README.md
CHANGED
|
@@ -107,6 +107,8 @@ Wechaty Web Panel 插件,让你的 wechaty 机器人快速接入 web 控制面
|
|
|
107
107
|
|
|
108
108
|
## 开始
|
|
109
109
|
|
|
110
|
+
> 环境node > 16
|
|
111
|
+
|
|
110
112
|
### Step 1: 安装
|
|
111
113
|
|
|
112
114
|
```
|
|
@@ -116,7 +118,7 @@ $ npm install wechaty-web-panel@latest wechaty@latest --save
|
|
|
116
118
|
如果安装长时间没有反应,可以尝试
|
|
117
119
|
|
|
118
120
|
```
|
|
119
|
-
npm install wechaty-web-panel@latest wechaty@latest --save
|
|
121
|
+
npm install wechaty-web-panel@latest wechaty@latest --save
|
|
120
122
|
```
|
|
121
123
|
|
|
122
124
|
### Step 2: 创建机器人并配置插件的`apiKey`和`apiSecret`
|
|
@@ -124,18 +126,23 @@ npm install wechaty-web-panel@latest wechaty@latest --save --canvas_binary_host_
|
|
|
124
126
|
```
|
|
125
127
|
$ vim mybot.js
|
|
126
128
|
|
|
127
|
-
const {
|
|
128
|
-
const WechatyWebPanelPlugin = require('
|
|
129
|
+
const {WechatyBuilder} = require('wechaty')
|
|
130
|
+
const WechatyWebPanelPlugin = require('../src/index')
|
|
131
|
+
|
|
129
132
|
const name = 'wechat-assistant'
|
|
130
|
-
const bot = new Wechaty({
|
|
131
|
-
name, // generate xxxx.memory-card.json and save login data for the next login
|
|
132
|
-
puppet: 'wechaty-puppet-wechat',
|
|
133
|
-
});
|
|
134
133
|
|
|
134
|
+
const bot = WechatyBuilder.build({
|
|
135
|
+
name, // generate xxxx.memory-card.json and save login data for the next login
|
|
136
|
+
puppet: 'wechaty-puppet-wechat',
|
|
137
|
+
})
|
|
135
138
|
bot
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
.use(WechatyWebPanelPlugin({
|
|
140
|
+
apiKey: '',
|
|
141
|
+
apiSecret: ''
|
|
142
|
+
}))
|
|
143
|
+
.start()
|
|
144
|
+
.catch((e) => console.error(e))
|
|
145
|
+
|
|
139
146
|
|
|
140
147
|
```
|
|
141
148
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wechaty-web-panel",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,32 +36,28 @@
|
|
|
36
36
|
"eslint-config-prettier": "^6.11.0",
|
|
37
37
|
"eslint-plugin-prettier": "^3.1.4",
|
|
38
38
|
"prettier": "^2.0.5",
|
|
39
|
-
"wechaty": "^
|
|
40
|
-
"wechaty-puppet-wechat": "^
|
|
39
|
+
"wechaty": "^1.13.12",
|
|
40
|
+
"wechaty-puppet-wechat": "^1.11.12"
|
|
41
41
|
},
|
|
42
42
|
"readme": "README.md",
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"
|
|
45
|
-
"mcanvas": "^2.0.8",
|
|
44
|
+
"ix": "^4.5.2",
|
|
46
45
|
"mqtt": "^4.2.6",
|
|
46
|
+
"mustache": "^4.2.0",
|
|
47
47
|
"nedb": "^1.8.0",
|
|
48
48
|
"node-schedule": "^1.3.2",
|
|
49
|
+
"puppeteer": "^13.3.2",
|
|
49
50
|
"qrcode-terminal": "^0.12.0",
|
|
50
51
|
"superagent": "^5.2.2",
|
|
51
|
-
"tencentcloud-sdk-nodejs": "^4.0.30"
|
|
52
|
-
"wechaty-plugin-contrib": "^0.14.17"
|
|
53
|
-
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"wechaty": "^0.68.1",
|
|
56
|
-
"wechaty-puppet-wechat": "^0.30.6"
|
|
52
|
+
"tencentcloud-sdk-nodejs": "^4.0.30"
|
|
57
53
|
},
|
|
58
54
|
"publishConfig": {
|
|
59
55
|
"registry": " https://registry.npmjs.org/"
|
|
60
56
|
},
|
|
61
57
|
"engines": {
|
|
62
|
-
"node": ">=
|
|
63
|
-
"npm": ">=
|
|
58
|
+
"node": ">=16.0",
|
|
59
|
+
"npm": ">=8.1"
|
|
64
60
|
},
|
|
65
|
-
"_id": "wechaty-web-panel@0.2
|
|
66
|
-
"_commitid": "
|
|
61
|
+
"_id": "wechaty-web-panel@1.0.2",
|
|
62
|
+
"_commitid": "7f308f9"
|
|
67
63
|
}
|
package/src/common/index.js
CHANGED
|
@@ -2,8 +2,8 @@ const { getNews, getTXweather, getSweetWord } = require('../proxy/api')
|
|
|
2
2
|
const { sendFriend, sendRoom, asyncData, getOne } = require('../proxy/aibotk')
|
|
3
3
|
const { getUser } = require('../common/userDb')
|
|
4
4
|
const { formatDate, getDay, MD5, groupArray, delay } = require('../lib')
|
|
5
|
-
const {
|
|
6
|
-
|
|
5
|
+
const { UrlLink, MiniProgram } = require('wechaty')
|
|
6
|
+
const { FileBox } = require('file-box')
|
|
7
7
|
/**
|
|
8
8
|
* 获取每日新闻内容
|
|
9
9
|
* @param {*} sortId 新闻资讯分类Id
|
|
@@ -12,7 +12,7 @@ const { FileBox, UrlLink, MiniProgram } = require('wechaty')
|
|
|
12
12
|
async function getEveryDayRoomContent(sortId, endWord = '微信小助手') {
|
|
13
13
|
let today = formatDate(new Date()) //获取今天的日期
|
|
14
14
|
let news = await getNews(sortId)
|
|
15
|
-
let content = `${today}
|
|
15
|
+
let content = `${today}\n${news}\n————————${endWord}`
|
|
16
16
|
return content
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ async function getEveryDayContent(date, city, endWord) {
|
|
|
28
28
|
let today = formatDate(new Date()) //获取今天的日期
|
|
29
29
|
let memorialDay = getDay(date) //获取纪念日天数
|
|
30
30
|
let sweetWord = await getSweetWord() // 土味情话
|
|
31
|
-
let str = `${today}
|
|
31
|
+
let str = `${today}\n我们在一起的第${memorialDay}天\n\n元气满满的一天开始啦,要开心噢^_^\n\n今日天气\n${weather.weatherTips}\n${weather.todayWeather}\n每日一句:\n${one}\n\n情话对你说:\n${sweetWord}\n\n————————${endWord}`
|
|
32
32
|
return str
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -42,9 +42,14 @@ async function updateContactInfo(that) {
|
|
|
42
42
|
const contactList = await that.Contact.findAll()
|
|
43
43
|
let res = []
|
|
44
44
|
const notids = ['filehelper', 'fmessage']
|
|
45
|
-
let realContact = hasWeixin
|
|
45
|
+
let realContact = hasWeixin
|
|
46
|
+
? contactList.filter((item) => {
|
|
47
|
+
const payload = item.payload || item._payload
|
|
48
|
+
return payload.type === 1 && payload.friend && !notids.includes(payload.id)
|
|
49
|
+
})
|
|
50
|
+
: contactList
|
|
46
51
|
for (let i of realContact) {
|
|
47
|
-
let contact = i.payload
|
|
52
|
+
let contact = i.payload || i._payload
|
|
48
53
|
let obj = {
|
|
49
54
|
robotId: hasWeixin ? contactSelf.weixin : MD5(contactSelf.name),
|
|
50
55
|
contactId: hasWeixin ? contact.id : MD5(contactSelf.name + contact.name + contact.alias + contact.province + contact.city + contact.gender),
|
|
@@ -75,7 +80,7 @@ async function updateContactInfo(that) {
|
|
|
75
80
|
*/
|
|
76
81
|
async function updateFriendInfo(list, num) {
|
|
77
82
|
const arr = groupArray(list, num)
|
|
78
|
-
for (let i =
|
|
83
|
+
for (let i = 0; i < arr.length; i++) {
|
|
79
84
|
const item = arr[i]
|
|
80
85
|
await sendFriend(item)
|
|
81
86
|
await delay(500)
|
|
@@ -92,7 +97,7 @@ async function updateRoomInfo(that) {
|
|
|
92
97
|
const roomList = await that.Room.findAll()
|
|
93
98
|
let res = []
|
|
94
99
|
for (let i of roomList) {
|
|
95
|
-
let room = i.payload
|
|
100
|
+
let room = i.payload || i._payload
|
|
96
101
|
let obj = {
|
|
97
102
|
robotId: hasWeixin ? contactSelf.weixin : MD5(contactSelf.name),
|
|
98
103
|
roomId: MD5(room.topic),
|
|
@@ -117,7 +122,7 @@ async function updateRoomInfo(that) {
|
|
|
117
122
|
*/
|
|
118
123
|
async function updateRoomsInfo(list, num) {
|
|
119
124
|
const arr = groupArray(list, num)
|
|
120
|
-
for (let i =
|
|
125
|
+
for (let i = 0; i < arr.length; i++) {
|
|
121
126
|
const item = arr[i]
|
|
122
127
|
await sendRoom(item)
|
|
123
128
|
await delay(500)
|
|
@@ -135,7 +140,7 @@ async function addRoomWelcomeSay(room, roomName, contactName, msg) {
|
|
|
135
140
|
if (msg.type === 1 && msg.content !== '') {
|
|
136
141
|
// 文字
|
|
137
142
|
console.log('回复内容', msg.content)
|
|
138
|
-
await room.say(`${roomName}:欢迎新朋友 @${contactName}
|
|
143
|
+
await room.say(`${roomName}:欢迎新朋友 @${contactName},\n${msg.content}`)
|
|
139
144
|
} else if (msg.type === 2 && msg.url !== '') {
|
|
140
145
|
// url文件
|
|
141
146
|
let obj = FileBox.fromUrl(msg.url)
|
package/src/handlers/on-login.js
CHANGED
|
@@ -2,7 +2,6 @@ const { delay, MD5 } = require('../lib')
|
|
|
2
2
|
const { getConfig, sendRobotInfo, sendError, putqn, setQrCode, updatePanelVersion } = require('../proxy/aibotk')
|
|
3
3
|
const { addUser } = require('../common/userDb')
|
|
4
4
|
const { initAllSchedule } = require('../task')
|
|
5
|
-
var pjson = require('../../package.json')
|
|
6
5
|
const { initMqtt } = require('../proxy/mqtt')
|
|
7
6
|
const { allConfig } = require('../common/configDb')
|
|
8
7
|
|
|
@@ -19,9 +18,10 @@ async function onLogin(user) {
|
|
|
19
18
|
await getConfig() // 获取配置文件
|
|
20
19
|
const config = await allConfig()
|
|
21
20
|
const { userId } = config.userInfo
|
|
21
|
+
const payload = user.payload || user._payload
|
|
22
22
|
const userInfo = {
|
|
23
|
-
...
|
|
24
|
-
robotId:
|
|
23
|
+
...payload,
|
|
24
|
+
robotId: payload.weixin || MD5(user.name()),
|
|
25
25
|
}
|
|
26
26
|
await addUser(userInfo) // 全局存储登录用户信息
|
|
27
27
|
const file = await user.avatar()
|
|
@@ -67,7 +67,7 @@ async function dispatchRoomFilterByMsgType(that, room, msg) {
|
|
|
67
67
|
const contactName = contact.name()
|
|
68
68
|
const roomName = await room.topic()
|
|
69
69
|
const type = msg.type()
|
|
70
|
-
const userSelfName = that.
|
|
70
|
+
const userSelfName = that.currentUser.name()
|
|
71
71
|
let content = ''
|
|
72
72
|
let replys = ''
|
|
73
73
|
let contactId = contact.id || '111'
|
package/src/lib/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const Crypto = require('crypto')
|
|
2
2
|
const schedule = require('node-schedule')
|
|
3
3
|
const fs = require('fs')
|
|
4
|
-
const { MCanvas, MImage } = require('mcanvas')
|
|
5
4
|
const { addRoom, getRoom } = require('../common/roomAvatarDb')
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -416,7 +415,7 @@ function filterContacts(contacts, query) {
|
|
|
416
415
|
let { name, alias, friend, type, gender, province, city, address } = query
|
|
417
416
|
return contacts.filter((item) => {
|
|
418
417
|
let arr = []
|
|
419
|
-
let
|
|
418
|
+
let payload = item.payload || item._payload
|
|
420
419
|
if (friend) {
|
|
421
420
|
let bool = Number(friend) === 1 ? true : false
|
|
422
421
|
arr.push(bool === payload.friend)
|
|
@@ -440,7 +439,7 @@ function formatContacts(data) {
|
|
|
440
439
|
let arr = data.map(function (item) {
|
|
441
440
|
// const file = await item.avatar()
|
|
442
441
|
// let avatar = await file.toBase64(file.name, true);
|
|
443
|
-
let payload = item.payload
|
|
442
|
+
let payload = item.payload || item._payload
|
|
444
443
|
return {
|
|
445
444
|
id: payload.id,
|
|
446
445
|
name: payload.name,
|
|
@@ -517,10 +516,10 @@ async function getRoomAvatarList(room, name) {
|
|
|
517
516
|
let res = []
|
|
518
517
|
console.log('正在努力获取群成员信息...')
|
|
519
518
|
for (let i of members) {
|
|
520
|
-
let member = i.payload
|
|
519
|
+
let member = i.payload || i._payload
|
|
521
520
|
try {
|
|
522
521
|
const avatar = await i.avatar()
|
|
523
|
-
if (avatar.
|
|
522
|
+
if (avatar._mediaType && avatar._name) {
|
|
524
523
|
const base64 = member.weixin ? member.avatar : await avatar.toDataURL()
|
|
525
524
|
let obj = {
|
|
526
525
|
img: base64,
|
|
@@ -541,7 +540,7 @@ async function getRoomAvatarList(room, name) {
|
|
|
541
540
|
console.log('获取群成员信息完成...')
|
|
542
541
|
return res
|
|
543
542
|
} catch (e) {
|
|
544
|
-
console.log('
|
|
543
|
+
console.log('获取群成员头像列表失败', e)
|
|
545
544
|
}
|
|
546
545
|
}
|
|
547
546
|
|
|
@@ -583,223 +582,6 @@ async function getRoomAvatar(roomObj, roomName, name) {
|
|
|
583
582
|
console.log('getRoomAvatar error', e)
|
|
584
583
|
}
|
|
585
584
|
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* 头像处理
|
|
589
|
-
* @param {*}} list
|
|
590
|
-
* @param {*} size
|
|
591
|
-
*/
|
|
592
|
-
async function cropImg(list, size = 74) {
|
|
593
|
-
try {
|
|
594
|
-
const arr = []
|
|
595
|
-
for (const i of list) {
|
|
596
|
-
try {
|
|
597
|
-
if (i.img) {
|
|
598
|
-
const im = new MImage(i.img)
|
|
599
|
-
im.compress({
|
|
600
|
-
quality: 1,
|
|
601
|
-
width: size,
|
|
602
|
-
height: size,
|
|
603
|
-
}).crop({
|
|
604
|
-
radius: size,
|
|
605
|
-
})
|
|
606
|
-
const bas64 = await im.draw({ type: 'png' })
|
|
607
|
-
arr.push({ img: bas64 })
|
|
608
|
-
}
|
|
609
|
-
} catch (error) {
|
|
610
|
-
console.log('处理头像失败', error)
|
|
611
|
-
continue
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return arr
|
|
615
|
-
} catch (error) {
|
|
616
|
-
console.log('cropImg error', error)
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
*
|
|
622
|
-
* @param {*} t 头像数组
|
|
623
|
-
* @param {*} param1
|
|
624
|
-
*/
|
|
625
|
-
function __beforePatternCircle(t, { size = 120, space = 24, circleSpace = 24, centerSizeMargin = 0 }) {
|
|
626
|
-
let i, r, n, s, o, c, l, p, u, g, m, d, h, f, v, b, w, y, C, _, k, I, x, S, j, q, D, z, P
|
|
627
|
-
for (u in ((i = size), (r = space), (n = circleSpace), (s = centerSizeMargin), (o = 1), (c = 0), (l = []), (p = r), t)) {
|
|
628
|
-
if (u > 0 && ((g = i / 2), (m = (i + n) * o), (m += s), (d = (2 * Math.PI * m) / (2 * g + r)), (d = Math.floor(d)), u > 0 && c === d - 1 ? (o++, (c = 0), l.push(d)) : c++, (h = t.length - 1 + ''), u === h && ((f = c), (v = c * i), c < d))) {
|
|
629
|
-
for (C in ((b = 0), (w = 0), (y = []), l)) {
|
|
630
|
-
C < l.length &&
|
|
631
|
-
((_ = l[C] * r),
|
|
632
|
-
_ >= i + r &&
|
|
633
|
-
((b += _),
|
|
634
|
-
(w += l[C]),
|
|
635
|
-
y.push({
|
|
636
|
-
level: C,
|
|
637
|
-
spaceUnit: _,
|
|
638
|
-
})))
|
|
639
|
-
}
|
|
640
|
-
v <= b && ((k = w + f === 0 ? 0 : (b - v) / (w + f)), (p = k))
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
for (j in ((I = 1), (x = 0), (S = 0), t)) j > 0 && ((q = i / 2), (D = (i + n) * I), (D += s), (z = (2 * Math.PI * D) / (2 * q + p)), (z = Math.floor(z)), t.length - j < z && ((P = t.length - 1 + ''), j === P && (S = 360 / (x + 1))), j > 0 && x === z - 1 ? (I++, (x = 0)) : x++)
|
|
644
|
-
return {
|
|
645
|
-
newSpace: p,
|
|
646
|
-
newRate: S,
|
|
647
|
-
lastCircleNumber: I,
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
function patternCircle(mc, t, info, i) {
|
|
652
|
-
let r, n, s, g, d, h, f, v, b, w, y, C, _, k, I, x, S, j, q
|
|
653
|
-
r = i.x
|
|
654
|
-
n = i.y
|
|
655
|
-
const o = i.centerSize || i.size
|
|
656
|
-
s = i.space
|
|
657
|
-
const c = o > i.size ? (o - i.size) / 2 : 0
|
|
658
|
-
const l = i.backWid
|
|
659
|
-
const p = i.backHei
|
|
660
|
-
const u = l / 2 // x中间坐标
|
|
661
|
-
g = p / 2 // y中间坐标
|
|
662
|
-
g = i.marginBottom ? p - i.marginBottom : g
|
|
663
|
-
r = u - i.size / 2
|
|
664
|
-
n = g - i.size / 2
|
|
665
|
-
const m = s
|
|
666
|
-
for (w in ((d = info), (s = d.newSpace), (h = d.newRate), (f = d.lastCircleNumber), (v = 1), (b = 0), t)) {
|
|
667
|
-
w > 0 &&
|
|
668
|
-
((y = i.size / 2),
|
|
669
|
-
(C = (i.size + m) * v),
|
|
670
|
-
(C += c),
|
|
671
|
-
(_ = (2 * Math.PI * C) / (2 * y + s)),
|
|
672
|
-
(_ = Math.floor(_)),
|
|
673
|
-
(k = 360 / _),
|
|
674
|
-
f === v && (k = h),
|
|
675
|
-
(I = ((2 * Math.PI) / 360) * k * b),
|
|
676
|
-
(x = u + Math.sin(I + (2 * Math.PI * 270) / 360) * C),
|
|
677
|
-
(S = g - Math.cos(I + (2 * Math.PI * 270) / 360) * C),
|
|
678
|
-
(r = x - y),
|
|
679
|
-
(n = S - y),
|
|
680
|
-
w > 0 && b === _ - 1 ? (v++, (b = 0)) : b++),
|
|
681
|
-
(j = i.size),
|
|
682
|
-
parseInt(w) === 0 && ((j = o), (r = u - o / 2), (n = g - o / 2)),
|
|
683
|
-
(q = t[w].img)
|
|
684
|
-
mc.add(q, {
|
|
685
|
-
width: j,
|
|
686
|
-
pos: {
|
|
687
|
-
x: r,
|
|
688
|
-
y: n,
|
|
689
|
-
scale: 1,
|
|
690
|
-
},
|
|
691
|
-
})
|
|
692
|
-
}
|
|
693
|
-
return mc
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* 绘制标题
|
|
698
|
-
* @param {*} mc
|
|
699
|
-
* @param {*} title
|
|
700
|
-
* @param {*} titleInfo
|
|
701
|
-
*/
|
|
702
|
-
|
|
703
|
-
function drawTitle(mc, title, titleInfo) {
|
|
704
|
-
mc.text(title, {
|
|
705
|
-
align: 'center',
|
|
706
|
-
width: '100%',
|
|
707
|
-
normalStyle: {
|
|
708
|
-
color: titleInfo.color,
|
|
709
|
-
lineHeight: titleInfo.fontSize,
|
|
710
|
-
font: `${titleInfo.fontSize}px Microsoft YaHei,sans-serif`,
|
|
711
|
-
},
|
|
712
|
-
pos: {
|
|
713
|
-
x: 0,
|
|
714
|
-
y: titleInfo.top,
|
|
715
|
-
},
|
|
716
|
-
})
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
async function generateRoomImg(list, options) {
|
|
720
|
-
try {
|
|
721
|
-
const { sizeInfo, titleInfo, background, roomName } = options
|
|
722
|
-
console.log('群合影生成中...')
|
|
723
|
-
list = await cropImg(list, sizeInfo.size)
|
|
724
|
-
const initOptions = {
|
|
725
|
-
title: titleInfo.title || roomName,
|
|
726
|
-
centerSize: sizeInfo.centerSize,
|
|
727
|
-
space: sizeInfo.space,
|
|
728
|
-
circleSpace: sizeInfo.space,
|
|
729
|
-
size: sizeInfo.size,
|
|
730
|
-
x: 0,
|
|
731
|
-
y: 0,
|
|
732
|
-
backWid: sizeInfo.width,
|
|
733
|
-
backHei: sizeInfo.height,
|
|
734
|
-
marginBottom: sizeInfo.bottom, // 距离底部高度
|
|
735
|
-
}
|
|
736
|
-
const mc = new MCanvas({
|
|
737
|
-
width: initOptions.backWid,
|
|
738
|
-
height: initOptions.backHei,
|
|
739
|
-
backgroundColor: '#ffffff',
|
|
740
|
-
})
|
|
741
|
-
mc.background(background, {
|
|
742
|
-
type: 'contain',
|
|
743
|
-
})
|
|
744
|
-
const info = __beforePatternCircle(list, initOptions)
|
|
745
|
-
patternCircle(mc, list, info, initOptions)
|
|
746
|
-
drawTitle(mc, initOptions.title, titleInfo)
|
|
747
|
-
const base64 = await mc.draw({ type: 'jpg', quality: 1 })
|
|
748
|
-
console.log('群合影生成成功!')
|
|
749
|
-
// var base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
|
750
|
-
// var dataBuffer = Buffer.from(base64Data, 'base64')
|
|
751
|
-
// fs.writeFile('image.jpg', dataBuffer, function (err) {
|
|
752
|
-
// if (err) {
|
|
753
|
-
// console.log(err)
|
|
754
|
-
// } else {
|
|
755
|
-
// console.log('保存成功!')
|
|
756
|
-
// }
|
|
757
|
-
// })
|
|
758
|
-
return base64
|
|
759
|
-
} catch (e) {
|
|
760
|
-
console.log('群合影生成失败', e)
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
async function generateAvatar(avatar, coverImg = 'http://image.xkboke.com/hat.png') {
|
|
765
|
-
try {
|
|
766
|
-
let mc = new MCanvas({
|
|
767
|
-
width: 880,
|
|
768
|
-
height: 880,
|
|
769
|
-
backgroundColor: '#ffffff',
|
|
770
|
-
})
|
|
771
|
-
mc.add(avatar, {
|
|
772
|
-
width: 860,
|
|
773
|
-
pos: {
|
|
774
|
-
x: 10,
|
|
775
|
-
y: 10,
|
|
776
|
-
scale: 1,
|
|
777
|
-
},
|
|
778
|
-
})
|
|
779
|
-
mc.add(coverImg, {
|
|
780
|
-
width: 880,
|
|
781
|
-
pos: {
|
|
782
|
-
x: 0,
|
|
783
|
-
y: 0,
|
|
784
|
-
scale: 1,
|
|
785
|
-
},
|
|
786
|
-
})
|
|
787
|
-
const base64 = await mc.draw({ type: 'jpg', quality: 1 })
|
|
788
|
-
// var base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
|
789
|
-
// var dataBuffer = Buffer.from(base64Data, 'base64')
|
|
790
|
-
// fs.writeFile('avatar.jpg', dataBuffer, function (err) {
|
|
791
|
-
// if (err) {
|
|
792
|
-
// console.log(err)
|
|
793
|
-
// } else {
|
|
794
|
-
// console.log('保存成功!')
|
|
795
|
-
// }
|
|
796
|
-
// })
|
|
797
|
-
return base64
|
|
798
|
-
} catch (e) {
|
|
799
|
-
console.log('头像生成失败', e)
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
|
|
803
585
|
module.exports = {
|
|
804
586
|
Base64Encode,
|
|
805
587
|
Base64Decode,
|
|
@@ -825,7 +607,5 @@ module.exports = {
|
|
|
825
607
|
getAllSchedule,
|
|
826
608
|
groupArray,
|
|
827
609
|
getRoomAvatarList,
|
|
828
|
-
generateRoomImg,
|
|
829
610
|
getRoomAvatar,
|
|
830
|
-
generateAvatar,
|
|
831
611
|
}
|
package/src/proxy/api.js
CHANGED
|
@@ -1,33 +1,8 @@
|
|
|
1
|
-
const cheerio = require('cheerio')
|
|
2
1
|
const { req, txReq } = require('./superagent')
|
|
3
2
|
const { EMOHOST, TULING, ONE, MEINV } = require('./config')
|
|
4
3
|
const { randomRange, MD5 } = require('../lib/index')
|
|
5
4
|
const { allConfig } = require('../common/configDb')
|
|
6
5
|
|
|
7
|
-
/**
|
|
8
|
-
* 获取每日一句,暂时弃用,已改为api调用
|
|
9
|
-
*/
|
|
10
|
-
async function getOne() {
|
|
11
|
-
try {
|
|
12
|
-
let option = {
|
|
13
|
-
spider: true,
|
|
14
|
-
method: 'GET',
|
|
15
|
-
url: ONE,
|
|
16
|
-
params: '',
|
|
17
|
-
}
|
|
18
|
-
let res = await req(option)
|
|
19
|
-
let $ = cheerio.load(res)
|
|
20
|
-
let todayOneList = $('#carousel-one .carousel-inner .item')
|
|
21
|
-
let todayOne = $(todayOneList[0])
|
|
22
|
-
.find('.fp-one-cita')
|
|
23
|
-
.text()
|
|
24
|
-
.replace(/(^\s*)|(\s*$)/g, '')
|
|
25
|
-
return todayOne
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.log('获取每日一句失败:', error)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
6
|
/**
|
|
32
7
|
* 天行图灵聊天机器人
|
|
33
8
|
* @param {*} word 发送内容
|
|
@@ -150,7 +125,7 @@ async function getRubbishType(word) {
|
|
|
150
125
|
} else if (content.newslist[0].type == 3) {
|
|
151
126
|
type = '是其他(干)垃圾'
|
|
152
127
|
}
|
|
153
|
-
let response = `${content.newslist[0].name}${type}
|
|
128
|
+
let response = `${content.newslist[0].name}${type}\n解释:${content.newslist[0].explain}\n主要包括:${content.newslist[0].contain}\n投放提示:${content.newslist[0].tip}`
|
|
154
129
|
return response
|
|
155
130
|
} else {
|
|
156
131
|
console.log('查询失败提示:', content.msg)
|
|
@@ -174,7 +149,7 @@ async function getSweetWord() {
|
|
|
174
149
|
let content = await txReq(option)
|
|
175
150
|
if (content.code === 200) {
|
|
176
151
|
let sweet = content.newslist[0].content
|
|
177
|
-
let str = sweet.replace('\r\n', '
|
|
152
|
+
let str = sweet.replace('\r\n', '\n')
|
|
178
153
|
return str
|
|
179
154
|
} else {
|
|
180
155
|
console.log('获取土情话接口失败', content.msg)
|
|
@@ -199,7 +174,7 @@ async function getTXweather(city) {
|
|
|
199
174
|
let todayInfo = content.newslist[0]
|
|
200
175
|
let obj = {
|
|
201
176
|
weatherTips: todayInfo.tips,
|
|
202
|
-
todayWeather: `今天:${todayInfo.weather}
|
|
177
|
+
todayWeather: `今天:${todayInfo.weather}\n温度:${todayInfo.lowest}/${todayInfo.highest}\n${todayInfo.wind} ${todayInfo.windspeed}\n\n`,
|
|
203
178
|
}
|
|
204
179
|
return obj
|
|
205
180
|
} else {
|
|
@@ -225,12 +200,12 @@ async function getNews(id) {
|
|
|
225
200
|
if (content.code === 200) {
|
|
226
201
|
let newList = content.newslist
|
|
227
202
|
let news = ''
|
|
228
|
-
let shortUrl = 'https://www.tianapi.com/weixin/news/?col=' + id
|
|
203
|
+
// let shortUrl = 'https://www.tianapi.com/weixin/news/?col=' + id
|
|
229
204
|
for (let i in newList) {
|
|
230
205
|
let num = parseInt(i) + 1
|
|
231
|
-
news = `${news}
|
|
206
|
+
news = `${news}\n${num}.${newList[i].title}`
|
|
232
207
|
}
|
|
233
|
-
return `${news}
|
|
208
|
+
return `${news}\n`
|
|
234
209
|
}
|
|
235
210
|
} catch (error) {
|
|
236
211
|
console.log('获取天行新闻失败', error)
|
|
@@ -250,7 +225,7 @@ async function getMingYan() {
|
|
|
250
225
|
let content = await txReq(option)
|
|
251
226
|
if (content.code === 200) {
|
|
252
227
|
let newList = content.newslist
|
|
253
|
-
let news = `${newList[0].content}
|
|
228
|
+
let news = `${newList[0].content}\n——————————${newList[0].author}`
|
|
254
229
|
return news
|
|
255
230
|
}
|
|
256
231
|
} catch (error) {
|
|
@@ -274,7 +249,7 @@ async function getStar(astro) {
|
|
|
274
249
|
let newList = content.newslist
|
|
275
250
|
let news = ''
|
|
276
251
|
for (let item of newList) {
|
|
277
|
-
news = `${news}${item.type}:${item.content}
|
|
252
|
+
news = `${news}${item.type}:${item.content}\n`
|
|
278
253
|
}
|
|
279
254
|
return news
|
|
280
255
|
}
|
|
@@ -339,7 +314,7 @@ async function getLunar(date) {
|
|
|
339
314
|
let content = await txReq(option)
|
|
340
315
|
if (content.code === 200) {
|
|
341
316
|
let item = content.newslist[0]
|
|
342
|
-
let news =
|
|
317
|
+
let news = `\n阳历:${item.gregoriandate}\n阴历:${item.lunardate}\n节日:${item.lunar_festival}\n适宜:${item.fitness}\n不宜:${item.taboo}\n神位:${item.shenwei}\n胎神:${item.taishen}\n冲煞:${item.chongsha}\n岁煞:${item.suisha}`
|
|
343
318
|
return news
|
|
344
319
|
}
|
|
345
320
|
} catch (error) {
|
|
@@ -360,7 +335,7 @@ async function getGoldReply() {
|
|
|
360
335
|
let content = await txReq(option)
|
|
361
336
|
if (content.code === 200) {
|
|
362
337
|
let item = content.newslist[0]
|
|
363
|
-
let news = `标题:"${item.title}"
|
|
338
|
+
let news = `标题:"${item.title}"\n回复:${item.content}`
|
|
364
339
|
return news
|
|
365
340
|
}
|
|
366
341
|
} catch (error) {
|
|
@@ -528,7 +503,9 @@ async function getNcov() {
|
|
|
528
503
|
if (content.code === 200) {
|
|
529
504
|
let newList = content.newslist[0].news
|
|
530
505
|
const riskarea = content.newslist[0].riskarea
|
|
531
|
-
const reply = `【疫情新闻暂时下线,目前只返回风险地区】\n\n全国风险地区\n\n【高风险地区】:\n${(riskarea.high && riskarea.high.length && riskarea.high.join('\n')) || '暂无'}\n【中风险地区】:\n${
|
|
506
|
+
const reply = `【疫情新闻暂时下线,目前只返回风险地区】\n\n全国风险地区\n\n【高风险地区】:\n${(riskarea.high && riskarea.high.length && riskarea.high.join('\n')) || '暂无'}\n【中风险地区】:\n${
|
|
507
|
+
(riskarea.mid && riskarea.mid.length && riskarea.mid.join('\n')) || '暂无'
|
|
508
|
+
}\n\n——————————数据来源:天行数据`
|
|
532
509
|
// let news = ''
|
|
533
510
|
// for (let i in newList) {
|
|
534
511
|
// let num = parseInt(i) + 1
|
|
@@ -560,7 +537,6 @@ async function getCname() {
|
|
|
560
537
|
}
|
|
561
538
|
}
|
|
562
539
|
module.exports = {
|
|
563
|
-
getOne,
|
|
564
540
|
getResByTXTL,
|
|
565
541
|
getResByTX,
|
|
566
542
|
getResByTL,
|
package/src/proxy/mqtt.js
CHANGED
|
@@ -53,7 +53,7 @@ async function initMqtt(that) {
|
|
|
53
53
|
}
|
|
54
54
|
} else if (content.target === 'Contact') {
|
|
55
55
|
console.log(`收到联系人:${content.alias || content.name}发送消息请求: ${content.message.content || content.message.url}`)
|
|
56
|
-
let contact = (await that.Contact.find({
|
|
56
|
+
let contact = (await that.Contact.find({ name: content.name })) || (await that.Contact.find({ alias: content.alias })) || (await that.Contact.find({ weixin: content.weixin })) // 获取你要发送的联系人
|
|
57
57
|
if (!contact) {
|
|
58
58
|
console.log(`查找不到联系人:${content.name || content.alias},请检查联系人名称是否正确`)
|
|
59
59
|
return
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成群合影
|
|
3
|
+
* @param list
|
|
4
|
+
* @param options
|
|
5
|
+
* @returns {Promise<unknown>}
|
|
6
|
+
*/
|
|
7
|
+
async function generateRoomImg({ list, options }) {
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param {*} t 头像数组
|
|
11
|
+
* @param {*} param1
|
|
12
|
+
*/
|
|
13
|
+
const __beforePatternCircle = function (t, { size = 120, space = 24, circleSpace = 24, centerSizeMargin = 0 }) {
|
|
14
|
+
let i, r, n, s, o, c, l, p, u, g, m, d, h, f, v, b, w, y, C, _, k, I, x, S, j, q, D, z, P
|
|
15
|
+
for (u in ((i = size), (r = space), (n = circleSpace), (s = centerSizeMargin), (o = 1), (c = 0), (l = []), (p = r), t)) {
|
|
16
|
+
if (u > 0 && ((g = i / 2), (m = (i + n) * o), (m += s), (d = (2 * Math.PI * m) / (2 * g + r)), (d = Math.floor(d)), u > 0 && c === d - 1 ? (o++, (c = 0), l.push(d)) : c++, (h = t.length - 1 + ''), u === h && ((f = c), (v = c * i), c < d))) {
|
|
17
|
+
for (C in ((b = 0), (w = 0), (y = []), l)) {
|
|
18
|
+
C < l.length &&
|
|
19
|
+
((_ = l[C] * r),
|
|
20
|
+
_ >= i + r &&
|
|
21
|
+
((b += _),
|
|
22
|
+
(w += l[C]),
|
|
23
|
+
y.push({
|
|
24
|
+
level: C,
|
|
25
|
+
spaceUnit: _,
|
|
26
|
+
})))
|
|
27
|
+
}
|
|
28
|
+
v <= b && ((k = w + f === 0 ? 0 : (b - v) / (w + f)), (p = k))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (j in ((I = 1), (x = 0), (S = 0), t)) j > 0 && ((q = i / 2), (D = (i + n) * I), (D += s), (z = (2 * Math.PI * D) / (2 * q + p)), (z = Math.floor(z)), t.length - j < z && ((P = t.length - 1 + ''), j === P && (S = 360 / (x + 1))), j > 0 && x === z - 1 ? (I++, (x = 0)) : x++)
|
|
32
|
+
return {
|
|
33
|
+
newSpace: p,
|
|
34
|
+
newRate: S,
|
|
35
|
+
lastCircleNumber: I,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const patternCircle = function (mc, t, info, i) {
|
|
40
|
+
let r, n, s, g, d, h, f, v, b, w, y, C, _, k, I, x, S, j, q
|
|
41
|
+
r = i.x
|
|
42
|
+
n = i.y
|
|
43
|
+
const o = i.centerSize || i.size
|
|
44
|
+
s = i.space
|
|
45
|
+
const c = o > i.size ? (o - i.size) / 2 : 0
|
|
46
|
+
const l = i.backWid
|
|
47
|
+
const p = i.backHei
|
|
48
|
+
const u = l / 2 // x中间坐标
|
|
49
|
+
g = p / 2 // y中间坐标
|
|
50
|
+
g = i.marginBottom ? p - i.marginBottom : g
|
|
51
|
+
r = u - i.size / 2
|
|
52
|
+
n = g - i.size / 2
|
|
53
|
+
const m = s
|
|
54
|
+
for (w in ((d = info), (s = d.newSpace), (h = d.newRate), (f = d.lastCircleNumber), (v = 1), (b = 0), t)) {
|
|
55
|
+
w > 0 &&
|
|
56
|
+
((y = i.size / 2),
|
|
57
|
+
(C = (i.size + m) * v),
|
|
58
|
+
(C += c),
|
|
59
|
+
(_ = (2 * Math.PI * C) / (2 * y + s)),
|
|
60
|
+
(_ = Math.floor(_)),
|
|
61
|
+
(k = 360 / _),
|
|
62
|
+
f === v && (k = h),
|
|
63
|
+
(I = ((2 * Math.PI) / 360) * k * b),
|
|
64
|
+
(x = u + Math.sin(I + (2 * Math.PI * 270) / 360) * C),
|
|
65
|
+
(S = g - Math.cos(I + (2 * Math.PI * 270) / 360) * C),
|
|
66
|
+
(r = x - y),
|
|
67
|
+
(n = S - y),
|
|
68
|
+
w > 0 && b === _ - 1 ? (v++, (b = 0)) : b++),
|
|
69
|
+
(j = i.size),
|
|
70
|
+
parseInt(w) === 0 && ((j = o), (r = u - o / 2), (n = g - o / 2)),
|
|
71
|
+
(q = t[w].img)
|
|
72
|
+
mc.add(q, {
|
|
73
|
+
width: j,
|
|
74
|
+
pos: {
|
|
75
|
+
x: r,
|
|
76
|
+
y: n,
|
|
77
|
+
scale: 1,
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
return mc
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 绘制标题
|
|
86
|
+
* @param {*} mc
|
|
87
|
+
* @param {*} title
|
|
88
|
+
* @param {*} titleInfo
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
const drawTitle = function (mc, title, titleInfo) {
|
|
92
|
+
mc.text(title, {
|
|
93
|
+
align: 'center',
|
|
94
|
+
width: '100%',
|
|
95
|
+
normalStyle: {
|
|
96
|
+
color: titleInfo.color,
|
|
97
|
+
lineHeight: titleInfo.fontSize,
|
|
98
|
+
font: `${titleInfo.fontSize}px Microsoft YaHei,sans-serif`,
|
|
99
|
+
},
|
|
100
|
+
pos: {
|
|
101
|
+
x: 0,
|
|
102
|
+
y: titleInfo.top,
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 头像处理
|
|
108
|
+
* @param {*}} list
|
|
109
|
+
* @param {*} size
|
|
110
|
+
*/
|
|
111
|
+
const cropImg = async function (list, size = 74, MImage) {
|
|
112
|
+
try {
|
|
113
|
+
const arr = []
|
|
114
|
+
if (list.length >= 100) {
|
|
115
|
+
console.log('群成员数量超过100,生成群合影速度可能比较慢,请耐心等待')
|
|
116
|
+
}
|
|
117
|
+
for (const i of list) {
|
|
118
|
+
try {
|
|
119
|
+
if (i.img) {
|
|
120
|
+
const im = new MImage(i.img)
|
|
121
|
+
im.compress({
|
|
122
|
+
quality: 1,
|
|
123
|
+
width: size,
|
|
124
|
+
height: size,
|
|
125
|
+
}).crop({
|
|
126
|
+
radius: size,
|
|
127
|
+
})
|
|
128
|
+
const bas64 = await im.draw({ type: 'png' })
|
|
129
|
+
arr.push({ img: bas64 })
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.log('处理头像失败', error)
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return arr
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.log('cropImg error', error)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return new Promise(async (resolve, reject) => {
|
|
143
|
+
let MCanvas = window.MCanvas.MCanvas
|
|
144
|
+
let MImage = window.MCanvas.MImage
|
|
145
|
+
try {
|
|
146
|
+
const { sizeInfo, titleInfo, background, roomName } = options
|
|
147
|
+
list = await cropImg(list, sizeInfo.size, MImage)
|
|
148
|
+
const initOptions = {
|
|
149
|
+
title: titleInfo.title || roomName,
|
|
150
|
+
centerSize: sizeInfo.centerSize,
|
|
151
|
+
space: sizeInfo.space,
|
|
152
|
+
circleSpace: sizeInfo.space,
|
|
153
|
+
size: sizeInfo.size,
|
|
154
|
+
x: 0,
|
|
155
|
+
y: 0,
|
|
156
|
+
backWid: sizeInfo.width,
|
|
157
|
+
backHei: sizeInfo.height,
|
|
158
|
+
marginBottom: sizeInfo.bottom, // 距离底部高度
|
|
159
|
+
}
|
|
160
|
+
const mc = new MCanvas({
|
|
161
|
+
width: initOptions.backWid,
|
|
162
|
+
height: initOptions.backHei,
|
|
163
|
+
backgroundColor: '#ffffff',
|
|
164
|
+
})
|
|
165
|
+
mc.background(background, {
|
|
166
|
+
type: 'contain',
|
|
167
|
+
})
|
|
168
|
+
const info = __beforePatternCircle(list, initOptions)
|
|
169
|
+
patternCircle(mc, list, info, initOptions)
|
|
170
|
+
drawTitle(mc, initOptions.title, titleInfo)
|
|
171
|
+
const base64 = await mc.draw({ type: 'jpg', quality: 1 })
|
|
172
|
+
console.log('群合影生成成功!')
|
|
173
|
+
// var base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
|
174
|
+
// var dataBuffer = Buffer.from(base64Data, 'base64')
|
|
175
|
+
// fs.writeFile('image.jpg', dataBuffer, function (err) {
|
|
176
|
+
// if (err) {
|
|
177
|
+
// console.log(err)
|
|
178
|
+
// } else {
|
|
179
|
+
// console.log('保存成功!')
|
|
180
|
+
// }
|
|
181
|
+
// })
|
|
182
|
+
resolve(base64)
|
|
183
|
+
} catch (e) {
|
|
184
|
+
console.log('群合影生成失败', e)
|
|
185
|
+
reject(`群合影生成失败:${e}`)
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function generateAvatar({ avatar, coverImg }) {
|
|
191
|
+
coverImg = coverImg || 'http://image.xkboke.com/hat.png'
|
|
192
|
+
return new Promise(async (resolve, reject) => {
|
|
193
|
+
try {
|
|
194
|
+
let MCanvas = window.MCanvas.MCanvas
|
|
195
|
+
let mc = new MCanvas({
|
|
196
|
+
width: 880,
|
|
197
|
+
height: 880,
|
|
198
|
+
backgroundColor: '#ffffff',
|
|
199
|
+
})
|
|
200
|
+
mc.add(avatar, {
|
|
201
|
+
width: 860,
|
|
202
|
+
pos: {
|
|
203
|
+
x: 10,
|
|
204
|
+
y: 10,
|
|
205
|
+
scale: 1,
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
mc.add(coverImg, {
|
|
209
|
+
width: 880,
|
|
210
|
+
pos: {
|
|
211
|
+
x: 0,
|
|
212
|
+
y: 0,
|
|
213
|
+
scale: 1,
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
const base64 = await mc.draw({ type: 'jpg', quality: 1 })
|
|
217
|
+
// var base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
|
218
|
+
// var dataBuffer = Buffer.from(base64Data, 'base64')
|
|
219
|
+
// fs.writeFile('avatar.jpg', dataBuffer, function (err) {
|
|
220
|
+
// if (err) {
|
|
221
|
+
// console.log(err)
|
|
222
|
+
// } else {
|
|
223
|
+
// console.log('保存成功!')
|
|
224
|
+
// }
|
|
225
|
+
// })
|
|
226
|
+
resolve(base64)
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.log('头像生成失败', e)
|
|
229
|
+
reject(`头像生成失败:${e}`)
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
module.exports = {
|
|
235
|
+
generateAvatar,
|
|
236
|
+
generateRoomImg,
|
|
237
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const puppeteer = require('puppeteer')
|
|
2
|
+
const mainConfig = require('./mainConfig')
|
|
3
|
+
class BrowserManage {
|
|
4
|
+
browserDestructionTimeout //清理浏览器实例
|
|
5
|
+
browserInstance //浏览器实例
|
|
6
|
+
browserState = 'closed' //浏览器状态
|
|
7
|
+
/**
|
|
8
|
+
* 用于长时间未进行操作时关闭浏览器实例
|
|
9
|
+
*/
|
|
10
|
+
scheduleBrowserForDestruction() {
|
|
11
|
+
clearTimeout(this.browserDestructionTimeout)
|
|
12
|
+
this.browserDestructionTimeout = setTimeout(async () => {
|
|
13
|
+
if (this.browserInstance) {
|
|
14
|
+
this.browserState = 'closed'
|
|
15
|
+
await this.browserInstance.close() //关闭浏览器实例
|
|
16
|
+
}
|
|
17
|
+
}, 5000)
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 用于长时间未进行操作时关闭浏览器实例
|
|
21
|
+
*/
|
|
22
|
+
async getBrowser() {
|
|
23
|
+
return new Promise(async (resolve, reject) => {
|
|
24
|
+
if (this.browserState === 'closed') {
|
|
25
|
+
this.browserInstance = await puppeteer.launch(mainConfig.config.puppeteer) //开启浏览器实例
|
|
26
|
+
this.browserState = 'open'
|
|
27
|
+
resolve(this.browserInstance)
|
|
28
|
+
}
|
|
29
|
+
if (this.browserState === 'open') {
|
|
30
|
+
if (this.browserInstance) {
|
|
31
|
+
resolve(this.browserInstance)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
module.exports = new BrowserManage()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const browserManage = require('./index')
|
|
2
|
+
const drawHelpers = require('./drawHelp')
|
|
3
|
+
|
|
4
|
+
const generateRoomImg = async function (passedOptions) {
|
|
5
|
+
const browser = await browserManage.getBrowser()
|
|
6
|
+
const page = (await browser.pages())[0]
|
|
7
|
+
// 添加 mcanvas cdn地址
|
|
8
|
+
let filePath = 'http://image.xkboke.com/pubilc/cdn/mcanvas.js'
|
|
9
|
+
await page.addScriptTag({
|
|
10
|
+
url: filePath,
|
|
11
|
+
})
|
|
12
|
+
page.on('console', (msg) => console.log(msg.type(), msg.text())) //监听页面console事件
|
|
13
|
+
const base64 = await page.evaluate(drawHelpers.generateRoomImg, passedOptions)
|
|
14
|
+
browserManage.scheduleBrowserForDestruction()
|
|
15
|
+
// await FileBox.fromBase64(base64).toFile('./test.png')
|
|
16
|
+
// const buffer = Buffer.from(base64, 'base64')
|
|
17
|
+
return base64 //返回Base64 编码的图片
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const generateAvatar = async function (passedOptions) {
|
|
21
|
+
const browser = await browserManage.getBrowser()
|
|
22
|
+
const page = (await browser.pages())[0]
|
|
23
|
+
// 添加 mcanvas cdn地址
|
|
24
|
+
let filePath = 'http://image.xkboke.com/pubilc/cdn/mcanvas.js'
|
|
25
|
+
await page.addScriptTag({
|
|
26
|
+
url: filePath,
|
|
27
|
+
})
|
|
28
|
+
page.on('console', (msg) => console.log(msg.type(), msg.text())) //监听页面console事件
|
|
29
|
+
const base64 = await page.evaluate(drawHelpers.generateAvatar, passedOptions)
|
|
30
|
+
browserManage.scheduleBrowserForDestruction()
|
|
31
|
+
// await FileBox.fromBase64(base64).toFile('./test.png')
|
|
32
|
+
return base64 //返回Base64 编码的图片
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
generateAvatar,
|
|
37
|
+
generateRoomImg,
|
|
38
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const api = require('../proxy/api')
|
|
2
|
-
const { getConfig,
|
|
3
|
-
const { getConstellation, msgArr, getAllSchedule,
|
|
2
|
+
const { getConfig, getRoomPhotoConfig, getMeiNv } = require('../proxy/aibotk')
|
|
3
|
+
const { getConstellation, msgArr, getAllSchedule, getRoomAvatar } = require('../lib')
|
|
4
|
+
const { generateAvatar, generateRoomImg } = require('../puppeteer-paint/lanuch')
|
|
4
5
|
const { initTaskLocalSchedule } = require('../task/index')
|
|
5
6
|
const { updateContactAndRoom, updateContactOnly, updateRoomOnly } = require('../common/index')
|
|
6
7
|
const { chatTencent } = require('../proxy/tencent')
|
|
7
|
-
const { log } = require('wechaty')
|
|
8
8
|
/**
|
|
9
9
|
* 根据事件名称分配不同的api处理,并获取返回内容
|
|
10
10
|
* @param {string} eName 事件名称
|
|
@@ -52,7 +52,7 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room) {
|
|
|
52
52
|
if (avatar.mimeType) {
|
|
53
53
|
// 如果图片类型正确再进行头像处理
|
|
54
54
|
let base64Text = await avatar.toDataURL()
|
|
55
|
-
url = await generateAvatar(base64Text)
|
|
55
|
+
url = await generateAvatar({ avatar: base64Text })
|
|
56
56
|
type = 3
|
|
57
57
|
} else {
|
|
58
58
|
content = '你的头像属于高维世界产物,小助手能力不足,无法解析,待我修炼后为你提供服务'
|
|
@@ -81,7 +81,7 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room) {
|
|
|
81
81
|
} else if (config.authList.length) {
|
|
82
82
|
if (config.authList.includes(name)) {
|
|
83
83
|
memberList = await getRoomAvatar(room, roomName, name)
|
|
84
|
-
const baseImg = await generateRoomImg(memberList, config)
|
|
84
|
+
const baseImg = await generateRoomImg({ list: memberList, options: config })
|
|
85
85
|
type = 3
|
|
86
86
|
url = baseImg
|
|
87
87
|
} else {
|
|
@@ -89,7 +89,7 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room) {
|
|
|
89
89
|
}
|
|
90
90
|
} else {
|
|
91
91
|
memberList = await getRoomAvatar(room, roomName, name)
|
|
92
|
-
const baseImg = await generateRoomImg(memberList, config)
|
|
92
|
+
const baseImg = await generateRoomImg({ list: memberList, options: config })
|
|
93
93
|
type = 3
|
|
94
94
|
url = baseImg
|
|
95
95
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const dispatch = require('./event-dispatch-service')
|
|
2
2
|
const { setSchedule, updateSchedule } = require('../proxy/aibotk')
|
|
3
|
-
const { contentDistinguish, setLocalSchedule, isRealDate
|
|
3
|
+
const { contentDistinguish, setLocalSchedule, isRealDate } = require('../lib')
|
|
4
|
+
const { generateAvatar } = require('../puppeteer-paint/lanuch')
|
|
4
5
|
const { addRoom } = require('../common/index')
|
|
5
6
|
|
|
6
7
|
function emptyMsg() {
|
|
@@ -1,6 +1,50 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { log } = require('wechaty')
|
|
2
|
+
const { Message } = require('wechaty').types
|
|
3
|
+
const Mustache = require('mustache')
|
|
4
|
+
|
|
5
|
+
function roomTalker(options) {
|
|
6
|
+
log.verbose('WechatyPluginContrib', 'roomTalker(%s)', JSON.stringify(options))
|
|
7
|
+
if (!options) {
|
|
8
|
+
return () => undefined
|
|
9
|
+
}
|
|
10
|
+
if (!Array.isArray(options)) {
|
|
11
|
+
options = [options]
|
|
12
|
+
}
|
|
13
|
+
const optionList = options
|
|
14
|
+
return async function talkRoom(room, contact, mustacheView) {
|
|
15
|
+
log.verbose('WechatyPluginContrib', 'roomTalker() talkRoom(%s, %s, %s)', room, contact || '', mustacheView ? JSON.stringify(mustacheView) : '')
|
|
16
|
+
for (const option of optionList) {
|
|
17
|
+
let msg
|
|
18
|
+
if (option instanceof Function) {
|
|
19
|
+
msg = await option(room, contact)
|
|
20
|
+
} else {
|
|
21
|
+
msg = option
|
|
22
|
+
}
|
|
2
23
|
|
|
3
|
-
|
|
24
|
+
if (!msg) {
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof msg === 'string') {
|
|
29
|
+
if (mustacheView) {
|
|
30
|
+
msg = Mustache.render(msg, mustacheView)
|
|
31
|
+
}
|
|
32
|
+
if (contact) {
|
|
33
|
+
await room.say(msg, contact)
|
|
34
|
+
} else {
|
|
35
|
+
await room.say(msg)
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
/**
|
|
39
|
+
* FIXME(huan): https://github.com/microsoft/TypeScript/issues/14107
|
|
40
|
+
*/
|
|
41
|
+
await room.say(msg)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await room.wechaty.sleep(1000)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
4
48
|
|
|
5
49
|
function messageMapper(mapperOptions, one) {
|
|
6
50
|
log.verbose('WechatyPluginContrib', 'messageMapper(%s)', typeof mapperOptions === 'function' ? 'function' : JSON.stringify(mapperOptions))
|
|
@@ -141,7 +185,7 @@ const bidirectionalMapper = async (message) => {
|
|
|
141
185
|
try {
|
|
142
186
|
const abbrRoomTopicForDevelopersHome = abbrRoomTopicByRegex(/\s*([^\s]*\s*[^\s]+)$/)
|
|
143
187
|
// Drop all messages if not Text
|
|
144
|
-
if (message.type() !== Message.
|
|
188
|
+
if (message.type() !== Message.Text) {
|
|
145
189
|
return
|
|
146
190
|
}
|
|
147
191
|
|
|
@@ -175,7 +219,7 @@ const unidirectionalMapper = async (message, one) => {
|
|
|
175
219
|
const room = message.room()
|
|
176
220
|
const topic = await room.topic()
|
|
177
221
|
switch (message.type()) {
|
|
178
|
-
case Message.
|
|
222
|
+
case Message.Text:
|
|
179
223
|
messageList.push(`${prefix}: ${message.text()}`)
|
|
180
224
|
break
|
|
181
225
|
|
|
@@ -187,7 +231,7 @@ const unidirectionalMapper = async (message, one) => {
|
|
|
187
231
|
* then we add a sender information for the destination rooms.
|
|
188
232
|
*/
|
|
189
233
|
if (topic === one) {
|
|
190
|
-
const type = Message
|
|
234
|
+
const type = Message[message.type()]
|
|
191
235
|
messageList.unshift(`${prefix}: ${type}`)
|
|
192
236
|
}
|
|
193
237
|
break
|
|
@@ -374,11 +418,11 @@ async function oneToMany(that, config, msg) {
|
|
|
374
418
|
*/
|
|
375
419
|
async function dispatchAsync(that, msg, list) {
|
|
376
420
|
try {
|
|
377
|
-
const userSelfName = that.
|
|
421
|
+
const userSelfName = that.currentUser.name()
|
|
378
422
|
const type = msg.type()
|
|
379
423
|
const content = msg.text()
|
|
380
424
|
const mentionSelf = content.includes(`@${userSelfName}`)
|
|
381
|
-
if (that.Message.
|
|
425
|
+
if (that.Message.Text === type && mentionSelf) {
|
|
382
426
|
// 如果内容中有提及机器人的内容,不进行转发
|
|
383
427
|
return
|
|
384
428
|
}
|
|
@@ -387,7 +431,7 @@ async function dispatchAsync(that, msg, list) {
|
|
|
387
431
|
config.blacklist = [async () => true]
|
|
388
432
|
if (config.forward === 1) {
|
|
389
433
|
config.map = bidirectionalMapper
|
|
390
|
-
config.whitelist = [async (message) => message.type() === Message.
|
|
434
|
+
config.whitelist = [async (message) => message.type() === Message.Text]
|
|
391
435
|
} else if (config.forward === 2) {
|
|
392
436
|
config.blacklist = []
|
|
393
437
|
config.map = unidirectionalMapper
|