douyin-danma-listener 0.1.1 → 0.2.0
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 +2 -1
- package/lib/index.js +64 -17
- package/lib/proto.js +51 -0
- package/package.json +2 -2
- package/types/types.d.ts +2 -0
package/README.md
CHANGED
|
@@ -29,8 +29,9 @@ client.connect();
|
|
|
29
29
|
|
|
30
30
|
- `autoStart` (boolean): 是否自动开始连接,默认为 `false`
|
|
31
31
|
- `autoReconnect` (number): 自动重连次数,默认为 `3`
|
|
32
|
-
- `heartbeatInterval` (number): 心跳包发送间隔,单位为毫秒,默认为 `
|
|
32
|
+
- `heartbeatInterval` (number): 心跳包发送间隔,单位为毫秒,默认为 `10000`
|
|
33
33
|
- `cookie` (string): 可选的 Cookie 字符串,某些直播间可能需要?
|
|
34
|
+
- `timeoutInterval` (number): 没有数据返回但`ws`未被主动关闭时超时后重新连接,单位为秒,默认`100`
|
|
34
35
|
|
|
35
36
|
## 事件
|
|
36
37
|
|
package/lib/index.js
CHANGED
|
@@ -22,18 +22,25 @@ class DouYinDanmaClient extends TypedEmitter {
|
|
|
22
22
|
roomId;
|
|
23
23
|
heartbeatInterval;
|
|
24
24
|
heartbeatTimer;
|
|
25
|
+
isHeartbeatRunning = false;
|
|
25
26
|
autoStart;
|
|
26
27
|
autoReconnect;
|
|
27
28
|
reconnectAttempts;
|
|
28
29
|
cookie;
|
|
30
|
+
timeoutInterval;
|
|
31
|
+
lastMessageTime;
|
|
32
|
+
timeoutTimer;
|
|
33
|
+
isTimeoutCheckRunning = false;
|
|
29
34
|
constructor(roomId, options = {}) {
|
|
30
35
|
super();
|
|
31
36
|
this.roomId = roomId;
|
|
32
|
-
this.heartbeatInterval = options.heartbeatInterval ??
|
|
37
|
+
this.heartbeatInterval = options.heartbeatInterval ?? 10000;
|
|
33
38
|
this.autoStart = options.autoStart ?? false;
|
|
34
39
|
this.autoReconnect = options.autoReconnect ?? 10;
|
|
35
40
|
this.reconnectAttempts = 0;
|
|
36
41
|
this.cookie = options.cookie;
|
|
42
|
+
this.timeoutInterval = options.timeoutInterval ?? 100000; // 默认100秒
|
|
43
|
+
this.lastMessageTime = Date.now();
|
|
37
44
|
if (this.autoStart) {
|
|
38
45
|
this.connect();
|
|
39
46
|
}
|
|
@@ -44,7 +51,7 @@ class DouYinDanmaClient extends TypedEmitter {
|
|
|
44
51
|
this.emit("error", new Error("获取抖音弹幕签名失败"));
|
|
45
52
|
return;
|
|
46
53
|
}
|
|
47
|
-
const cookies = this.cookie
|
|
54
|
+
const cookies = this.cookie || (await getCookie());
|
|
48
55
|
this.ws = new WebSocket(url, {
|
|
49
56
|
headers: {
|
|
50
57
|
Cookie: cookies,
|
|
@@ -53,27 +60,19 @@ class DouYinDanmaClient extends TypedEmitter {
|
|
|
53
60
|
this.ws.on("open", () => {
|
|
54
61
|
this.emit("open");
|
|
55
62
|
this.startHeartbeat();
|
|
63
|
+
this.startTimeoutCheck();
|
|
56
64
|
});
|
|
57
65
|
this.ws.on("message", (data) => {
|
|
66
|
+
this.lastMessageTime = Date.now();
|
|
58
67
|
this.decode(data);
|
|
59
68
|
});
|
|
60
69
|
this.ws.on("close", () => {
|
|
61
70
|
this.emit("close");
|
|
62
|
-
this.
|
|
63
|
-
if (this.reconnectAttempts < this.autoReconnect) {
|
|
64
|
-
this.reconnectAttempts++;
|
|
65
|
-
this.connect();
|
|
66
|
-
this.emit("reconnect", this.reconnectAttempts);
|
|
67
|
-
}
|
|
71
|
+
this.reconnect();
|
|
68
72
|
});
|
|
69
73
|
this.ws.on("error", (error) => {
|
|
70
74
|
this.emit("error", error);
|
|
71
|
-
this.
|
|
72
|
-
if (this.reconnectAttempts < this.autoReconnect) {
|
|
73
|
-
this.reconnectAttempts++;
|
|
74
|
-
this.connect();
|
|
75
|
-
this.emit("reconnect", this.reconnectAttempts);
|
|
76
|
-
}
|
|
75
|
+
this.reconnect();
|
|
77
76
|
});
|
|
78
77
|
}
|
|
79
78
|
send(data) {
|
|
@@ -87,16 +86,64 @@ class DouYinDanmaClient extends TypedEmitter {
|
|
|
87
86
|
return;
|
|
88
87
|
}
|
|
89
88
|
this.reconnectAttempts = this.autoReconnect;
|
|
89
|
+
this.stopHeartbeat();
|
|
90
|
+
this.stopTimeoutCheck();
|
|
90
91
|
this.ws.close();
|
|
91
92
|
}
|
|
92
93
|
startHeartbeat() {
|
|
94
|
+
if (this.isHeartbeatRunning) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.stopHeartbeat();
|
|
98
|
+
this.isHeartbeatRunning = true;
|
|
93
99
|
this.heartbeatTimer = setInterval(() => {
|
|
94
|
-
this.
|
|
95
|
-
|
|
100
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
101
|
+
this.emit("heartbeat");
|
|
102
|
+
this.send(":\x02hb");
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log("连接未就绪,当前状态:", this.ws.readyState);
|
|
106
|
+
}
|
|
96
107
|
}, this.heartbeatInterval);
|
|
97
108
|
}
|
|
98
109
|
stopHeartbeat() {
|
|
99
|
-
|
|
110
|
+
if (this.heartbeatTimer) {
|
|
111
|
+
clearInterval(this.heartbeatTimer);
|
|
112
|
+
this.isHeartbeatRunning = false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
startTimeoutCheck() {
|
|
116
|
+
if (this.isTimeoutCheckRunning) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.stopTimeoutCheck();
|
|
120
|
+
this.isTimeoutCheckRunning = true;
|
|
121
|
+
// 重置最后消息时间,给连接一些初始化时间
|
|
122
|
+
this.lastMessageTime = Date.now();
|
|
123
|
+
this.timeoutTimer = setInterval(() => {
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
if (now - this.lastMessageTime > this.timeoutInterval) {
|
|
126
|
+
console.log("No message received for too long, reconnecting...");
|
|
127
|
+
// 在重连前重置时间,避免立即触发下一次重连
|
|
128
|
+
this.lastMessageTime = now;
|
|
129
|
+
this.reconnect();
|
|
130
|
+
}
|
|
131
|
+
}, 1000);
|
|
132
|
+
}
|
|
133
|
+
stopTimeoutCheck() {
|
|
134
|
+
if (this.timeoutTimer) {
|
|
135
|
+
clearInterval(this.timeoutTimer);
|
|
136
|
+
this.isTimeoutCheckRunning = false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
reconnect() {
|
|
140
|
+
this.stopHeartbeat();
|
|
141
|
+
this.stopTimeoutCheck();
|
|
142
|
+
if (this.reconnectAttempts < this.autoReconnect) {
|
|
143
|
+
this.reconnectAttempts++;
|
|
144
|
+
this.connect();
|
|
145
|
+
this.emit("reconnect", this.reconnectAttempts);
|
|
146
|
+
}
|
|
100
147
|
}
|
|
101
148
|
async handleMessage() { }
|
|
102
149
|
/**
|
package/lib/proto.js
CHANGED
|
@@ -1046,6 +1046,7 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1046
1046
|
* @property {douyin.ICommon|null} [common] ChatMessage common
|
|
1047
1047
|
* @property {douyin.IUser|null} [user] ChatMessage user
|
|
1048
1048
|
* @property {string|null} [content] ChatMessage content
|
|
1049
|
+
* @property {number|Long|null} [eventTime] ChatMessage eventTime
|
|
1049
1050
|
*/
|
|
1050
1051
|
/**
|
|
1051
1052
|
* Constructs a new ChatMessage.
|
|
@@ -1082,6 +1083,13 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1082
1083
|
* @instance
|
|
1083
1084
|
*/
|
|
1084
1085
|
ChatMessage.prototype.content = "";
|
|
1086
|
+
/**
|
|
1087
|
+
* ChatMessage eventTime.
|
|
1088
|
+
* @member {number|Long} eventTime
|
|
1089
|
+
* @memberof douyin.ChatMessage
|
|
1090
|
+
* @instance
|
|
1091
|
+
*/
|
|
1092
|
+
ChatMessage.prototype.eventTime = $util.Long ? $util.Long.fromBits(0, 0, true) : 0;
|
|
1085
1093
|
/**
|
|
1086
1094
|
* Creates a new ChatMessage instance using the specified properties.
|
|
1087
1095
|
* @function create
|
|
@@ -1111,6 +1119,8 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1111
1119
|
$root.douyin.User.encode(message.user, writer.uint32(/* id 2, wireType 2 =*/ 18).fork()).ldelim();
|
|
1112
1120
|
if (message.content != null && Object.hasOwnProperty.call(message, "content"))
|
|
1113
1121
|
writer.uint32(/* id 3, wireType 2 =*/ 26).string(message.content);
|
|
1122
|
+
if (message.eventTime != null && Object.hasOwnProperty.call(message, "eventTime"))
|
|
1123
|
+
writer.uint32(/* id 15, wireType 0 =*/ 120).uint64(message.eventTime);
|
|
1114
1124
|
return writer;
|
|
1115
1125
|
};
|
|
1116
1126
|
/**
|
|
@@ -1155,6 +1165,10 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1155
1165
|
message.content = reader.string();
|
|
1156
1166
|
break;
|
|
1157
1167
|
}
|
|
1168
|
+
case 15: {
|
|
1169
|
+
message.eventTime = reader.uint64();
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1158
1172
|
default:
|
|
1159
1173
|
reader.skipType(tag & 7);
|
|
1160
1174
|
break;
|
|
@@ -1201,6 +1215,12 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1201
1215
|
if (message.content != null && message.hasOwnProperty("content"))
|
|
1202
1216
|
if (!$util.isString(message.content))
|
|
1203
1217
|
return "content: string expected";
|
|
1218
|
+
if (message.eventTime != null && message.hasOwnProperty("eventTime"))
|
|
1219
|
+
if (!$util.isInteger(message.eventTime) &&
|
|
1220
|
+
!(message.eventTime &&
|
|
1221
|
+
$util.isInteger(message.eventTime.low) &&
|
|
1222
|
+
$util.isInteger(message.eventTime.high)))
|
|
1223
|
+
return "eventTime: integer|Long expected";
|
|
1204
1224
|
return null;
|
|
1205
1225
|
};
|
|
1206
1226
|
/**
|
|
@@ -1227,6 +1247,15 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1227
1247
|
}
|
|
1228
1248
|
if (object.content != null)
|
|
1229
1249
|
message.content = String(object.content);
|
|
1250
|
+
if (object.eventTime != null)
|
|
1251
|
+
if ($util.Long)
|
|
1252
|
+
(message.eventTime = $util.Long.fromValue(object.eventTime)).unsigned = true;
|
|
1253
|
+
else if (typeof object.eventTime === "string")
|
|
1254
|
+
message.eventTime = parseInt(object.eventTime, 10);
|
|
1255
|
+
else if (typeof object.eventTime === "number")
|
|
1256
|
+
message.eventTime = object.eventTime;
|
|
1257
|
+
else if (typeof object.eventTime === "object")
|
|
1258
|
+
message.eventTime = new $util.LongBits(object.eventTime.low >>> 0, object.eventTime.high >>> 0).toNumber(true);
|
|
1230
1259
|
return message;
|
|
1231
1260
|
};
|
|
1232
1261
|
/**
|
|
@@ -1246,6 +1275,17 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1246
1275
|
object.common = null;
|
|
1247
1276
|
object.user = null;
|
|
1248
1277
|
object.content = "";
|
|
1278
|
+
if ($util.Long) {
|
|
1279
|
+
let long = new $util.Long(0, 0, true);
|
|
1280
|
+
object.eventTime =
|
|
1281
|
+
options.longs === String
|
|
1282
|
+
? long.toString()
|
|
1283
|
+
: options.longs === Number
|
|
1284
|
+
? long.toNumber()
|
|
1285
|
+
: long;
|
|
1286
|
+
}
|
|
1287
|
+
else
|
|
1288
|
+
object.eventTime = options.longs === String ? "0" : 0;
|
|
1249
1289
|
}
|
|
1250
1290
|
if (message.common != null && message.hasOwnProperty("common"))
|
|
1251
1291
|
object.common = $root.douyin.Common.toObject(message.common, options);
|
|
@@ -1253,6 +1293,17 @@ export const douyin = ($root.douyin = (() => {
|
|
|
1253
1293
|
object.user = $root.douyin.User.toObject(message.user, options);
|
|
1254
1294
|
if (message.content != null && message.hasOwnProperty("content"))
|
|
1255
1295
|
object.content = message.content;
|
|
1296
|
+
if (message.eventTime != null && message.hasOwnProperty("eventTime"))
|
|
1297
|
+
if (typeof message.eventTime === "number")
|
|
1298
|
+
object.eventTime =
|
|
1299
|
+
options.longs === String ? String(message.eventTime) : message.eventTime;
|
|
1300
|
+
else
|
|
1301
|
+
object.eventTime =
|
|
1302
|
+
options.longs === String
|
|
1303
|
+
? $util.Long.prototype.toString.call(message.eventTime)
|
|
1304
|
+
: options.longs === Number
|
|
1305
|
+
? new $util.LongBits(message.eventTime.low >>> 0, message.eventTime.high >>> 0).toNumber(true)
|
|
1306
|
+
: message.eventTime;
|
|
1256
1307
|
return object;
|
|
1257
1308
|
};
|
|
1258
1309
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "douyin-danma-listener",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "douyin danma listener",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./types/index.d.ts",
|
|
@@ -43,6 +43,6 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc",
|
|
45
45
|
"watch": "tsc -w",
|
|
46
|
-
"gen:proto": "pbjs -t static-module -w es6 -o src/
|
|
46
|
+
"gen:proto": "pbjs -t static-module -w es6 -o src/proto.js src/dy.proto"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/types/types.d.ts
CHANGED