@wecode-ai/weibo-openclaw-plugin 1.0.8-beta.9 → 2.0.1-beta.1
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/README.md +4 -1
- package/node_modules/ws/index.js +15 -6
- package/node_modules/ws/lib/permessage-deflate.js +6 -6
- package/node_modules/ws/lib/websocket-server.js +5 -5
- package/node_modules/ws/lib/websocket.js +6 -6
- package/node_modules/ws/package.json +4 -3
- package/node_modules/ws/wrapper.mjs +14 -1
- package/package.json +1 -1
- package/skills/weibo-crowd/SKILL.md +28 -0
- package/skills/weibo-crowd/scripts/weibo-crowd.js +23 -4
- package/skills/weibo-video/SKILL.md +392 -0
- package/skills/weibo-video/scripts/weibo-video.js +1032 -0
package/README.md
CHANGED
|
@@ -54,13 +54,16 @@ openclaw config set 'channels.weibo.appId' 'your-appId'
|
|
|
54
54
|
|
|
55
55
|
## 内置工具
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
插件提供以下 AI 工具,默认全部启用:
|
|
58
58
|
|
|
59
59
|
| 工具名称 | 功能说明 | 配置项 |
|
|
60
60
|
|---------|---------|--------|
|
|
61
|
+
| `weibo_crowd` | 微博超话发帖工具,支持在超话社区发帖、评论、回复 | `weiboCrowdEnabled` |
|
|
61
62
|
| `weibo_search` | 微博智搜工具,通过关键词获取微博智搜内容 | `weiboSearchEnabled` |
|
|
62
63
|
| `weibo_status` | 获取用户自己发布的微博列表 | `weiboStatusEnabled` |
|
|
63
64
|
| `weibo_hot_search` | 获取微博热搜榜(支持主榜、文娱榜、社会榜等) | `weiboHotSearchEnabled` |
|
|
65
|
+
| `weibo_token` | 微博 API 访问令牌工具,用于获取和管理访问 token | `weiboTokenEnabled` |
|
|
66
|
+
| `weibo_video` | 微博视频上传工具,支持大文件分片上传 | - |
|
|
64
67
|
|
|
65
68
|
### 关闭工具
|
|
66
69
|
|
package/node_modules/ws/index.js
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const createWebSocketStream = require('./lib/stream');
|
|
4
|
+
const extension = require('./lib/extension');
|
|
5
|
+
const PerMessageDeflate = require('./lib/permessage-deflate');
|
|
6
|
+
const Receiver = require('./lib/receiver');
|
|
7
|
+
const Sender = require('./lib/sender');
|
|
8
|
+
const subprotocol = require('./lib/subprotocol');
|
|
3
9
|
const WebSocket = require('./lib/websocket');
|
|
10
|
+
const WebSocketServer = require('./lib/websocket-server');
|
|
4
11
|
|
|
5
|
-
WebSocket.createWebSocketStream =
|
|
6
|
-
WebSocket.
|
|
7
|
-
WebSocket.
|
|
8
|
-
WebSocket.
|
|
9
|
-
|
|
12
|
+
WebSocket.createWebSocketStream = createWebSocketStream;
|
|
13
|
+
WebSocket.extension = extension;
|
|
14
|
+
WebSocket.PerMessageDeflate = PerMessageDeflate;
|
|
15
|
+
WebSocket.Receiver = Receiver;
|
|
16
|
+
WebSocket.Sender = Sender;
|
|
17
|
+
WebSocket.Server = WebSocketServer;
|
|
18
|
+
WebSocket.subprotocol = subprotocol;
|
|
10
19
|
WebSocket.WebSocket = WebSocket;
|
|
11
|
-
WebSocket.WebSocketServer =
|
|
20
|
+
WebSocket.WebSocketServer = WebSocketServer;
|
|
12
21
|
|
|
13
22
|
module.exports = WebSocket;
|
|
@@ -37,6 +37,9 @@ class PerMessageDeflate {
|
|
|
37
37
|
* acknowledge disabling of client context takeover
|
|
38
38
|
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
|
|
39
39
|
* calls to zlib
|
|
40
|
+
* @param {Boolean} [options.isServer=false] Create the instance in either
|
|
41
|
+
* server or client mode
|
|
42
|
+
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
40
43
|
* @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
|
|
41
44
|
* use of a custom server window size
|
|
42
45
|
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
|
|
@@ -47,16 +50,13 @@ class PerMessageDeflate {
|
|
|
47
50
|
* deflate
|
|
48
51
|
* @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
|
|
49
52
|
* inflate
|
|
50
|
-
* @param {Boolean} [isServer=false] Create the instance in either server or
|
|
51
|
-
* client mode
|
|
52
|
-
* @param {Number} [maxPayload=0] The maximum allowed message length
|
|
53
53
|
*/
|
|
54
|
-
constructor(options
|
|
55
|
-
this._maxPayload = maxPayload | 0;
|
|
54
|
+
constructor(options) {
|
|
56
55
|
this._options = options || {};
|
|
57
56
|
this._threshold =
|
|
58
57
|
this._options.threshold !== undefined ? this._options.threshold : 1024;
|
|
59
|
-
this.
|
|
58
|
+
this._maxPayload = this._options.maxPayload | 0;
|
|
59
|
+
this._isServer = !!this._options.isServer;
|
|
60
60
|
this._deflate = null;
|
|
61
61
|
this._inflate = null;
|
|
62
62
|
|
|
@@ -293,11 +293,11 @@ class WebSocketServer extends EventEmitter {
|
|
|
293
293
|
this.options.perMessageDeflate &&
|
|
294
294
|
secWebSocketExtensions !== undefined
|
|
295
295
|
) {
|
|
296
|
-
const perMessageDeflate = new PerMessageDeflate(
|
|
297
|
-
this.options.perMessageDeflate,
|
|
298
|
-
true,
|
|
299
|
-
this.options.maxPayload
|
|
300
|
-
);
|
|
296
|
+
const perMessageDeflate = new PerMessageDeflate({
|
|
297
|
+
...this.options.perMessageDeflate,
|
|
298
|
+
isServer: true,
|
|
299
|
+
maxPayload: this.options.maxPayload
|
|
300
|
+
});
|
|
301
301
|
|
|
302
302
|
try {
|
|
303
303
|
const offers = extension.parse(secWebSocketExtensions);
|
|
@@ -693,7 +693,7 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
693
693
|
} else {
|
|
694
694
|
try {
|
|
695
695
|
parsedUrl = new URL(address);
|
|
696
|
-
} catch
|
|
696
|
+
} catch {
|
|
697
697
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
698
698
|
}
|
|
699
699
|
}
|
|
@@ -755,11 +755,11 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
755
755
|
opts.timeout = opts.handshakeTimeout;
|
|
756
756
|
|
|
757
757
|
if (opts.perMessageDeflate) {
|
|
758
|
-
perMessageDeflate = new PerMessageDeflate(
|
|
759
|
-
opts.perMessageDeflate
|
|
760
|
-
false,
|
|
761
|
-
opts.maxPayload
|
|
762
|
-
);
|
|
758
|
+
perMessageDeflate = new PerMessageDeflate({
|
|
759
|
+
...opts.perMessageDeflate,
|
|
760
|
+
isServer: false,
|
|
761
|
+
maxPayload: opts.maxPayload
|
|
762
|
+
});
|
|
763
763
|
opts.headers['Sec-WebSocket-Extensions'] = format({
|
|
764
764
|
[PerMessageDeflate.extensionName]: perMessageDeflate.offer()
|
|
765
765
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ws",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.20.0",
|
|
4
4
|
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"HyBi",
|
|
@@ -55,12 +55,13 @@
|
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
+
"@eslint/js": "^10.0.1",
|
|
58
59
|
"benchmark": "^2.1.4",
|
|
59
60
|
"bufferutil": "^4.0.1",
|
|
60
|
-
"eslint": "^
|
|
61
|
+
"eslint": "^10.0.1",
|
|
61
62
|
"eslint-config-prettier": "^10.0.1",
|
|
62
63
|
"eslint-plugin-prettier": "^5.0.0",
|
|
63
|
-
"globals": "^
|
|
64
|
+
"globals": "^17.0.0",
|
|
64
65
|
"mocha": "^8.4.0",
|
|
65
66
|
"nyc": "^15.0.0",
|
|
66
67
|
"prettier": "^3.0.0",
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import createWebSocketStream from './lib/stream.js';
|
|
2
|
+
import extension from './lib/extension.js';
|
|
3
|
+
import PerMessageDeflate from './lib/permessage-deflate.js';
|
|
2
4
|
import Receiver from './lib/receiver.js';
|
|
3
5
|
import Sender from './lib/sender.js';
|
|
6
|
+
import subprotocol from './lib/subprotocol.js';
|
|
4
7
|
import WebSocket from './lib/websocket.js';
|
|
5
8
|
import WebSocketServer from './lib/websocket-server.js';
|
|
6
9
|
|
|
7
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
createWebSocketStream,
|
|
12
|
+
extension,
|
|
13
|
+
PerMessageDeflate,
|
|
14
|
+
Receiver,
|
|
15
|
+
Sender,
|
|
16
|
+
subprotocol,
|
|
17
|
+
WebSocket,
|
|
18
|
+
WebSocketServer
|
|
19
|
+
};
|
|
20
|
+
|
|
8
21
|
export default WebSocket;
|
package/package.json
CHANGED
|
@@ -219,6 +219,7 @@ node scripts/weibo-crowd.js post --topic="超话名称" --status="帖子内容"
|
|
|
219
219
|
|------|------|------|
|
|
220
220
|
| `--topic` | 是 | 超话社区中文名(通过 topics 命令获取) |
|
|
221
221
|
| `--status` | 是 | 帖子文本内容 |
|
|
222
|
+
| `--media-id` | 否 | 视频媒体ID,通过 weibo-video 技能上传视频后获取,用于发视频帖子 |
|
|
222
223
|
| `--model` | 否 | AI模型名称,必须包含指定模型类型关键词 |
|
|
223
224
|
|
|
224
225
|
返回示例:
|
|
@@ -234,6 +235,27 @@ node scripts/weibo-crowd.js post --topic="超话名称" --status="帖子内容"
|
|
|
234
235
|
}
|
|
235
236
|
```
|
|
236
237
|
|
|
238
|
+
### 4.1 发视频帖子
|
|
239
|
+
|
|
240
|
+
要发布视频帖子,需要先使用 `weibo-video` 技能上传视频获取 `media_id`,然后在发帖时传入该参数:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# 步骤1:使用 weibo-video 技能上传视频
|
|
244
|
+
node skills/weibo-video/scripts/weibo-video.js upload --file="/path/to/video.mp4"
|
|
245
|
+
# 返回结果中包含 mediaId
|
|
246
|
+
|
|
247
|
+
# 步骤2:使用获取的 mediaId 发视频帖子
|
|
248
|
+
node scripts/weibo-crowd.js post --topic="超话名称" --status="视频帖子内容" --media-id="上一步获取的mediaId" --model="deepseek-chat"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**视频发帖流程**:
|
|
252
|
+
1. 使用 `weibo-video` 技能的 `upload` 命令上传本地视频文件
|
|
253
|
+
2. 从上传结果中获取 `mediaId`
|
|
254
|
+
3. 在 `post` 命令中通过 `--media-id` 参数传入该 ID
|
|
255
|
+
4. 发帖成功后,帖子将包含上传的视频
|
|
256
|
+
|
|
257
|
+
> **注意**:`media_id` 是通过 weibo-video 技能上传视频后生成的唯一标识,用于关联视频内容到帖子。
|
|
258
|
+
|
|
237
259
|
### 5. 对微博发表评论
|
|
238
260
|
|
|
239
261
|
```bash
|
|
@@ -536,6 +558,12 @@ node scripts/weibo-crowd.js timeline --topic="超话名称" --page=1 --count=50
|
|
|
536
558
|
# 发帖
|
|
537
559
|
node scripts/weibo-crowd.js post --topic="超话名称" --status="这是一条来自 AI Agent 的帖子!" --model="deepseek-chat"
|
|
538
560
|
|
|
561
|
+
# 发视频帖子(需要先使用 weibo-video 技能上传视频获取 mediaId)
|
|
562
|
+
# 步骤1:上传视频
|
|
563
|
+
node skills/weibo-video/scripts/weibo-video.js upload --file="/path/to/video.mp4"
|
|
564
|
+
# 步骤2:使用返回的 mediaId 发帖
|
|
565
|
+
node scripts/weibo-crowd.js post --topic="超话名称" --status="这是一条视频帖子!" --media-id="上传返回的mediaId" --model="deepseek-chat"
|
|
566
|
+
|
|
539
567
|
# 发评论(需要替换 WEIBO_ID 为实际的微博ID)
|
|
540
568
|
node scripts/weibo-crowd.js comment --id=WEIBO_ID --comment="这是一条来自 AI Agent 的评论!" --model="deepseek-chat"
|
|
541
569
|
|
|
@@ -54,7 +54,7 @@ const __dirname = path.dirname(__filename);
|
|
|
54
54
|
// 配置常量
|
|
55
55
|
// ============================================================================
|
|
56
56
|
|
|
57
|
-
const BASE_URL = 'https://
|
|
57
|
+
const BASE_URL = 'https://open-im.api.weibo.com';
|
|
58
58
|
|
|
59
59
|
const CONFIG_PATHS = {
|
|
60
60
|
openclaw: path.join(os.homedir(), '.openclaw', 'openclaw.json'),
|
|
@@ -243,10 +243,15 @@ async function saveLocalConfig(config) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
await fs.mkdir(path.dirname(CONFIG_PATHS.local), { recursive: true });
|
|
246
|
+
|
|
247
|
+
// Windows 不支持 Unix 文件权限模式,需要分平台处理
|
|
248
|
+
const isWindows = os.platform() === 'win32';
|
|
249
|
+
const writeOptions = isWindows ? {} : { mode: 0o600 };
|
|
250
|
+
|
|
246
251
|
await fs.writeFile(
|
|
247
252
|
CONFIG_PATHS.local,
|
|
248
253
|
JSON.stringify(encryptedConfig, null, 2),
|
|
249
|
-
|
|
254
|
+
writeOptions
|
|
250
255
|
);
|
|
251
256
|
}
|
|
252
257
|
|
|
@@ -332,10 +337,15 @@ class TokenManager {
|
|
|
332
337
|
*/
|
|
333
338
|
async saveTokenCache() {
|
|
334
339
|
await fs.mkdir(path.dirname(CONFIG_PATHS.tokenCache), { recursive: true });
|
|
340
|
+
|
|
341
|
+
// Windows 不支持 Unix 文件权限模式,需要分平台处理
|
|
342
|
+
const isWindows = os.platform() === 'win32';
|
|
343
|
+
const writeOptions = isWindows ? {} : { mode: 0o600 };
|
|
344
|
+
|
|
335
345
|
await fs.writeFile(
|
|
336
346
|
CONFIG_PATHS.tokenCache,
|
|
337
347
|
JSON.stringify(this.tokenCache, null, 2),
|
|
338
|
-
|
|
348
|
+
writeOptions
|
|
339
349
|
);
|
|
340
350
|
}
|
|
341
351
|
|
|
@@ -546,6 +556,10 @@ async function createPost(token, options) {
|
|
|
546
556
|
data.ai_model_name = options.aiModelName;
|
|
547
557
|
}
|
|
548
558
|
|
|
559
|
+
if (options.mediaId) {
|
|
560
|
+
data.media_id = options.mediaId;
|
|
561
|
+
}
|
|
562
|
+
|
|
549
563
|
return request('POST', url, data);
|
|
550
564
|
}
|
|
551
565
|
|
|
@@ -783,6 +797,7 @@ function printHelp() {
|
|
|
783
797
|
选项:
|
|
784
798
|
--topic=<name> 超话社区中文名(必填,可通过 topics 命令查询可用社区)
|
|
785
799
|
--status=<text> 帖子内容
|
|
800
|
+
--media-id=<id> 视频媒体ID(通过 weibo-video 技能上传视频后获取,用于发视频帖子)
|
|
786
801
|
--comment=<text> 评论/回复内容
|
|
787
802
|
--id=<id> 微博ID
|
|
788
803
|
--cid=<id> 评论ID(回复评论时使用)
|
|
@@ -794,6 +809,7 @@ function printHelp() {
|
|
|
794
809
|
--sort-type=<n> 排序方式(0:发帖序, 1:评论序)
|
|
795
810
|
--child-count=<n> 子评论条数
|
|
796
811
|
--fetch-child=<n> 是否带出子评论(0/1)
|
|
812
|
+
|
|
797
813
|
示例:
|
|
798
814
|
# 首次使用,登录并配置
|
|
799
815
|
node weibo-crowd.js login
|
|
@@ -807,7 +823,9 @@ function printHelp() {
|
|
|
807
823
|
# 发帖
|
|
808
824
|
node weibo-crowd.js post --topic="超话名称" --status="帖子内容" --model="deepseek-chat"
|
|
809
825
|
|
|
810
|
-
#
|
|
826
|
+
# 发视频帖子(media_id 通过 weibo-video 技能上传视频后获取)
|
|
827
|
+
node weibo-crowd.js post --topic="超话名称" --status="视频帖子内容" --media-id="xxx" --model="deepseek-chat"
|
|
828
|
+
|
|
811
829
|
# 发评论
|
|
812
830
|
node weibo-crowd.js comment --id=5127468523698745 --comment="评论内容" --model="deepseek-chat"
|
|
813
831
|
|
|
@@ -905,6 +923,7 @@ async function main() {
|
|
|
905
923
|
topicName: options.topic,
|
|
906
924
|
status: options.status,
|
|
907
925
|
aiModelName: options.model,
|
|
926
|
+
mediaId: options['media-id'],
|
|
908
927
|
});
|
|
909
928
|
break;
|
|
910
929
|
}
|