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 CHANGED
@@ -29,8 +29,9 @@ client.connect();
29
29
 
30
30
  - `autoStart` (boolean): 是否自动开始连接,默认为 `false`
31
31
  - `autoReconnect` (number): 自动重连次数,默认为 `3`
32
- - `heartbeatInterval` (number): 心跳包发送间隔,单位为毫秒,默认为 `5000`
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 ?? 5000;
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 ?? (await getCookie());
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.stopHeartbeat();
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.stopHeartbeat();
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.emit("heartbeat");
95
- this.send(":\x02hb");
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
- clearInterval(this.heartbeatTimer);
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.1.1",
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/danma/proto.js src/danma/dy.proto"
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
@@ -111,6 +111,8 @@ export interface ChatMessage {
111
111
  common: Common & { method: "WebcastChatMessage" };
112
112
  user: User;
113
113
  content: string;
114
+ /** 秒级时间戳 */
115
+ eventTime: string;
114
116
  // giftImage: {
115
117
  // urlListList: string[];
116
118
  // width: string;