floating-live 0.8.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.
Files changed (57) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +62 -0
  3. package/index.d.ts +2 -0
  4. package/index.js +6 -0
  5. package/package.json +29 -0
  6. package/plugin/acfun/acfunLive.d.ts +74 -0
  7. package/plugin/acfun/acfunLive.js +236 -0
  8. package/plugin/acfun/index.d.ts +3 -0
  9. package/plugin/acfun/index.js +12 -0
  10. package/plugin/bilibili/bilibiliLive.d.ts +58 -0
  11. package/plugin/bilibili/bilibiliLive.js +421 -0
  12. package/plugin/bilibili/index.d.ts +3 -0
  13. package/plugin/bilibili/index.js +12 -0
  14. package/plugin/chat/ChatCommand.d.ts +9 -0
  15. package/plugin/chat/ChatCommand.js +39 -0
  16. package/plugin/chat/ChatFilter.d.ts +9 -0
  17. package/plugin/chat/ChatFilter.js +44 -0
  18. package/plugin/chat/chatProcessor.d.ts +12 -0
  19. package/plugin/chat/chatProcessor.js +24 -0
  20. package/plugin/chatPrint/chatPrint.d.ts +21 -0
  21. package/plugin/chatPrint/chatPrint.js +111 -0
  22. package/plugin/chatPrint/index.d.ts +4 -0
  23. package/plugin/chatPrint/index.js +8 -0
  24. package/plugin/consoleEvent/index.d.ts +3 -0
  25. package/plugin/consoleEvent/index.js +39 -0
  26. package/plugin/msgSave/index.d.ts +4 -0
  27. package/plugin/msgSave/index.js +31 -0
  28. package/plugin/msgSave/msgSave.d.ts +22 -0
  29. package/plugin/msgSave/msgSave.js +40 -0
  30. package/src/controller/Message.d.ts +9 -0
  31. package/src/controller/Message.js +15 -0
  32. package/src/controller/Room.d.ts +32 -0
  33. package/src/controller/Room.js +110 -0
  34. package/src/controller/index.d.ts +39 -0
  35. package/src/controller/index.js +74 -0
  36. package/src/index.d.ts +33 -0
  37. package/src/index.js +50 -0
  38. package/src/lib/Registerable.d.ts +27 -0
  39. package/src/lib/Registerable.js +67 -0
  40. package/src/types/message/AttributeInfo.d.ts +64 -0
  41. package/src/types/message/AttributeInfo.js +2 -0
  42. package/src/types/message/MessageData.d.ts +80 -0
  43. package/src/types/message/MessageData.js +2 -0
  44. package/src/types/message/MessageInfo.d.ts +123 -0
  45. package/src/types/message/MessageInfo.js +2 -0
  46. package/src/types/plugin/Plugin.d.ts +3 -0
  47. package/src/types/plugin/Plugin.js +2 -0
  48. package/src/types/room/LiveInfo.d.ts +24 -0
  49. package/src/types/room/LiveInfo.js +2 -0
  50. package/src/types/room/LiveRoom.d.ts +20 -0
  51. package/src/types/room/LiveRoom.js +2 -0
  52. package/src/types/room/PlatformInfo.d.ts +38 -0
  53. package/src/types/room/PlatformInfo.js +2 -0
  54. package/src/types/room/RoomInfo.d.ts +16 -0
  55. package/src/types/room/RoomInfo.js +2 -0
  56. package/src/utils/getRoomInfo.d.ts +4 -0
  57. package/src/utils/getRoomInfo.js +25 -0
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Floating Live
2
+ 一个用于处理和保存直播弹幕的Node.js小工具,开箱即用。
3
+
4
+ 目前支持bilibili和AcFun的直播弹幕,不同平台的弹幕会转换为同一种格式便于保存。
5
+
6
+ 项目仍在开发中,功能尚未完善,目前除了记录保存直播弹幕外暂时没有别的用处啦,敬请期待。
7
+
8
+ 注意:当前项目未进入正式版本阶段,程序结构及导出数据结构可能随时改动,**非常不建议用于正式项目中**。
9
+
10
+ ## 使用方法
11
+ ### npm安装
12
+ ```
13
+ npm install floating-live
14
+ ```
15
+ ``` javascript
16
+ // 导入FloatingLive
17
+ const FloatingLive = require("floating-live")
18
+ // 导入bilibili房间生成插件
19
+ const bilibili = require("floating-live/plugin/bilibili")
20
+
21
+ // 创建一个FloatingLive实例
22
+ const live = new FloatingLive()
23
+ // 注册插件
24
+ live.registerPlugin("bilibili", bilibili)
25
+ // 添加房间
26
+ live.controller.addRoom({platform: "bilibili", id: 6})
27
+ // 打开
28
+ live.controller.start()
29
+ ```
30
+
31
+ ### 拆包即用模式
32
+ * 下载并安装 `Node.js` ,建议下载最新LTS版本(如果已经安装可跳过这一步)。
33
+ * 下载该项目的zip压缩包,解压,并在项目根目录下新建一个名为 `save` 的文件夹。
34
+ * 在项目根目录的控制台输入下列命令,安装所有依赖包。
35
+ ```
36
+ npm install
37
+ ```
38
+ #### 运行Demo文件
39
+ * 打开demo/demo.ts
40
+ ``` typescript
41
+ // ...
42
+ const config = {
43
+ rooms: [
44
+ {
45
+ platform: "bilibili", // 直播平台
46
+ id: 2064239, // 直播间号
47
+ },
48
+ ],
49
+ };
50
+ // ...
51
+ ```
52
+ * 根据需要修改直播平台和直播间号,目前支持的 `platform` 值有:`acfun`、`bilibili`(注意是小写),也可以通过自定义插件添加直播平台
53
+ * 在项目根目录的控制台输入下列命令:
54
+ ```
55
+ npm run test
56
+ ```
57
+ 即可接收来自平台的直播弹幕。
58
+
59
+ ## 感谢
60
+ ### 开源库
61
+ * [simon300000/bilibili-live-ws](https://github.com/simon300000/bilibili-live-ws/):与bilibili直播建立Websocket连接并解码数据包
62
+ * [ACFUN-FOSS/ac-danmu](https://github.com/ACFUN-FOSS/ac-danmu.js):与AcFun直播建立Websocket连接并解码数据包
package/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import FloatingLiving from "./src";
2
+ export = FloatingLiving;
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ const src_1 = __importDefault(require("./src"));
6
+ module.exports = src_1.default;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "floating-live",
3
+ "version": "0.8.0",
4
+ "type": "commonjs",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "author": "Minteea",
8
+ "license": "GPLv3",
9
+ "scripts": {
10
+ "tsc": "tsc -b",
11
+ "clear": "rimraf index.js index.d.ts src/**/*.js src/**/*.d.ts plugin/**/*.js plugin/**/*.d.ts",
12
+ "test": "npm run clear && ts-node demo/demo.ts",
13
+ "build-test": "npm run build && node demo/demo.js",
14
+ "build": "npm run clear && npm run tsc",
15
+ "prepare": "npm run build"
16
+ },
17
+ "dependencies": {
18
+ "acfun-live-danmaku": "^0.6.1",
19
+ "axios": "^0.26.0",
20
+ "bilibili-live-ws": "^6.0.3"
21
+ },
22
+ "devDependencies": {
23
+ "@types/websocket": "^1.0.5",
24
+ "@types/ws": "^8.5.3",
25
+ "rimraf": "^3.0.2",
26
+ "ts-node": "^10.9.1",
27
+ "typescript": "^4.8.4"
28
+ }
29
+ }
@@ -0,0 +1,74 @@
1
+ /// <reference types="node" />
2
+ import { MedalInfo, UserInfo } from "../../src/types/message/AttributeInfo";
3
+ import LiveRoom from "../../src/types/room/LiveRoom";
4
+ import AcClient from "acfun-live-danmaku/client";
5
+ import { EventEmitter } from "events";
6
+ import { LiveInfo } from "../../src/types/room/LiveInfo";
7
+ declare class acfunLive extends EventEmitter implements LiveRoom {
8
+ /** 平台id */
9
+ readonly platform: string;
10
+ /** 房间id */
11
+ readonly id: number;
12
+ /** 直播信息 */
13
+ live: LiveInfo;
14
+ /** 主播信息 */
15
+ anchor: UserInfo;
16
+ /** 直播间弹幕api模块 */
17
+ client: AcClient | null;
18
+ /** 是否为打开状态 */
19
+ opening: boolean;
20
+ private wsInit;
21
+ /** 直播间是否可用 */
22
+ get available(): boolean;
23
+ constructor(id: number, open?: boolean);
24
+ getInfo(): Promise<void>;
25
+ /** 开启直播间监听 */
26
+ open(): Promise<void>;
27
+ /** 初始化直播服务端监听 */
28
+ private initWS;
29
+ close(): void;
30
+ destory(): void;
31
+ /** 根据守护徽章字符串获取粉丝牌信息 */
32
+ getMedal(badge: string): MedalInfo | null;
33
+ /** 文本信息(Comment) */
34
+ msg_Comment(data: {
35
+ sendTimeMs: string;
36
+ userInfo: {
37
+ userIdentity: any;
38
+ badge: string;
39
+ nickname: any;
40
+ userId: string;
41
+ };
42
+ content: any;
43
+ }): void;
44
+ /** 礼物信息(Gift) */
45
+ msg_Gift(data: {
46
+ sendTimeMs: string;
47
+ user: {
48
+ userIdentity: any;
49
+ badge: string;
50
+ nickname: any;
51
+ userId: string;
52
+ };
53
+ giftName: any;
54
+ giftId: string;
55
+ count: any;
56
+ value: string;
57
+ }): void;
58
+ /** 互动信息 */
59
+ msg_Interact(data: {
60
+ sendTimeMs: string;
61
+ userInfo: {
62
+ userIdentity: any;
63
+ badge: string;
64
+ nickname: any;
65
+ userId: string;
66
+ };
67
+ }, type: "entry" | "like" | "follow" | "share" | "join"): void;
68
+ msg_LiveClosed(): void;
69
+ msg_LiveBanned(): void;
70
+ msg_DisplayInfo(data: any): void;
71
+ emitMsg(data: any): void;
72
+ emitOrigin(data: any): void;
73
+ }
74
+ export default acfunLive;
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const acfun_live_danmaku_1 = __importDefault(require("acfun-live-danmaku"));
7
+ const events_1 = require("events");
8
+ const axios_1 = __importDefault(require("axios"));
9
+ class acfunLive extends events_1.EventEmitter {
10
+ constructor(id, open = false) {
11
+ super();
12
+ /** 平台id */
13
+ this.platform = "acfun";
14
+ /** 直播信息 */
15
+ this.live = {
16
+ /** 直播标题 */
17
+ title: "",
18
+ /** 分区 */
19
+ area: [],
20
+ /** 封面 */
21
+ cover: "",
22
+ /** 直播状态 */
23
+ status: "off",
24
+ /** 开始直播时间 */
25
+ start_time: 0
26
+ };
27
+ /** 主播信息 */
28
+ this.anchor = { name: "", id: 0 };
29
+ /** 直播间弹幕api模块 */
30
+ this.client = null;
31
+ /** 是否为打开状态 */
32
+ this.opening = false;
33
+ this.wsInit = false;
34
+ this.platform = "acfun";
35
+ this.id = id; // 直播间号
36
+ this.anchor.id = id; // 主播uid
37
+ this.getInfo().then(() => {
38
+ if (open)
39
+ this.open();
40
+ });
41
+ console.log("连接直播间");
42
+ }
43
+ /** 直播间是否可用 */
44
+ get available() {
45
+ return Boolean(this.client);
46
+ }
47
+ ;
48
+ async getInfo() {
49
+ if (!this.client) {
50
+ this.client = await (0, acfun_live_danmaku_1.default)(this.id) || null;
51
+ if (this.client) {
52
+ this.live.status = "live";
53
+ this.live.start_time = this.client.liveStartTime;
54
+ this.live.title = this.client.caption; // bug
55
+ this.live.cover = `https://tx2.a.kwimgs.com/bs2/ztlc/cover_${this.client.liveId}_raw.jpg`;
56
+ }
57
+ await axios_1.default
58
+ .get(`https://live.acfun.cn/rest/pc-direct/user/userInfo?userId=${this.id}`)
59
+ .then((res) => {
60
+ let profile = res.data.profile;
61
+ this.anchor.avatar = profile.headUrl;
62
+ this.anchor.name = profile.name;
63
+ })
64
+ .catch((error) => {
65
+ console.error(error);
66
+ });
67
+ this.emit("info");
68
+ }
69
+ // 暂不能在连接房间后更新信息
70
+ }
71
+ /** 开启直播间监听 */
72
+ async open() {
73
+ if (this.opening || !this.available)
74
+ return;
75
+ if (!this.wsInit) {
76
+ this.initWS();
77
+ }
78
+ //启动websocket连接
79
+ this.opening = true;
80
+ this.client.wsStart();
81
+ this.emit("open");
82
+ }
83
+ /** 初始化直播服务端监听 */
84
+ async initWS() {
85
+ if (!this.client)
86
+ return;
87
+ let client = this.client;
88
+ client.on("EnterRoomAck", () => {
89
+ console.log("[acfun-live-danmaku] 已连接AcFun直播间");
90
+ this.live.status = "live";
91
+ });
92
+ client.on("RecentComment", (comments) => {
93
+ //当前弹幕列表
94
+ });
95
+ client.on("Comment", (danmaku) => {
96
+ //收到的弹幕
97
+ this.msg_Comment(danmaku);
98
+ });
99
+ client.on("Gift", (gift) => { this.msg_Gift(gift); });
100
+ client.on("UserEnterRoom", (entry) => { this.msg_Interact(entry, "entry"); });
101
+ client.on("Like", (like) => { this.msg_Interact(like, "like"); });
102
+ client.on("JoinClub", (join) => { this.msg_Interact(join, "join"); });
103
+ client.on("DisplayInfo", (info) => { this.msg_DisplayInfo(info); });
104
+ client.on("LiveClosed", (end) => { this.msg_LiveClosed(); });
105
+ client.on("LiveBanned", (end) => { this.msg_LiveBanned(); });
106
+ this.wsInit = true;
107
+ }
108
+ close() {
109
+ if (!this.opening)
110
+ return;
111
+ this.opening = false;
112
+ this.client?.wsClose();
113
+ this.emit("close");
114
+ }
115
+ destory() {
116
+ this.close();
117
+ this.removeAllListeners();
118
+ }
119
+ ;
120
+ /** 根据守护徽章字符串获取粉丝牌信息 */
121
+ getMedal(badge) {
122
+ if (badge) {
123
+ let medalInfo = JSON.parse(badge).medalInfo;
124
+ return {
125
+ name: medalInfo.clubName,
126
+ id: medalInfo.uperId,
127
+ level: medalInfo.level,
128
+ };
129
+ }
130
+ else {
131
+ return null;
132
+ }
133
+ }
134
+ /** 文本信息(Comment) */
135
+ msg_Comment(data) {
136
+ let danmaku = {
137
+ platform: "acfun",
138
+ room: this.id,
139
+ local_timestamp: new Date().valueOf(),
140
+ type: "text",
141
+ info: {
142
+ text: data.content,
143
+ user: {
144
+ name: data.userInfo.nickname,
145
+ id: parseInt(data.userInfo.userId),
146
+ medal: this.getMedal(data.userInfo.badge),
147
+ },
148
+ timestamp: parseInt(data.sendTimeMs),
149
+ },
150
+ };
151
+ this.emitMsg(danmaku);
152
+ }
153
+ /** 礼物信息(Gift) */
154
+ msg_Gift(data) {
155
+ let gift = {
156
+ platform: "acfun",
157
+ room: this.id,
158
+ type: "gift",
159
+ local_timestamp: new Date().valueOf(),
160
+ info: {
161
+ user: {
162
+ name: data.user.nickname,
163
+ id: parseInt(data.user.userId),
164
+ medal: this.getMedal(data.user.badge),
165
+ },
166
+ gift: {
167
+ name: data.giftName,
168
+ id: parseInt(data.giftId),
169
+ num: data.count,
170
+ currency: "coin",
171
+ value: parseInt(data.value), // 总价值
172
+ },
173
+ timestamp: parseInt(data.sendTimeMs),
174
+ },
175
+ };
176
+ this.emitMsg(gift);
177
+ }
178
+ /** 互动信息 */
179
+ msg_Interact(data, type) {
180
+ let like = {
181
+ platform: "acfun",
182
+ room: this.id,
183
+ type: type,
184
+ local_timestamp: new Date().valueOf(),
185
+ info: {
186
+ user: {
187
+ name: data.userInfo.nickname,
188
+ id: parseInt(data.userInfo.userId),
189
+ medal: this.getMedal(data.userInfo.badge),
190
+ },
191
+ timestamp: parseInt(data.sendTimeMs),
192
+ },
193
+ };
194
+ this.emitMsg(like);
195
+ }
196
+ msg_LiveClosed() {
197
+ let off = {
198
+ platform: "acfun",
199
+ room: this.id,
200
+ type: "live_end",
201
+ local_timestamp: new Date().valueOf(),
202
+ info: {
203
+ status: "off"
204
+ }
205
+ };
206
+ this.live.status = "off";
207
+ this.client = null;
208
+ this.emitMsg(off);
209
+ }
210
+ msg_LiveBanned() {
211
+ let cut = {
212
+ platform: "acfun",
213
+ room: this.id,
214
+ type: "live_cut",
215
+ local_timestamp: new Date().valueOf(),
216
+ info: {
217
+ message: ""
218
+ }
219
+ };
220
+ this.live.status = "off";
221
+ this.client = null;
222
+ this.emitMsg(cut);
223
+ }
224
+ msg_DisplayInfo(data) {
225
+ // this.toData(msg)
226
+ }
227
+ emitMsg(data) {
228
+ // 一般消息
229
+ this.emit("msg", data);
230
+ }
231
+ emitOrigin(data) {
232
+ // 源消息
233
+ this.emit("origin", data);
234
+ }
235
+ }
236
+ exports.default = acfunLive;
@@ -0,0 +1,3 @@
1
+ import FloatingLive from "../../src/index";
2
+ declare const _default: (ctx: FloatingLive) => void;
3
+ export = _default;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ const acfunLive_1 = __importDefault(require("./acfunLive"));
6
+ module.exports = (ctx) => {
7
+ ctx.helper.roomGenerator.register("acfun", (id, open) => {
8
+ let key = `acfun:${Number(id)}`;
9
+ let room = new acfunLive_1.default(Number(id), open);
10
+ return { key, room };
11
+ });
12
+ };
@@ -0,0 +1,58 @@
1
+ /// <reference types="node" />
2
+ import { UserInfo } from "../../src/types/message/AttributeInfo";
3
+ import { KeepLiveWS } from "bilibili-live-ws";
4
+ import { EventEmitter } from "events";
5
+ import LiveRoom from "../../src/types/room/LiveRoom";
6
+ import { LiveInfo } from "../../src/types/room/LiveInfo";
7
+ declare class bilibiliLive extends EventEmitter implements LiveRoom {
8
+ /** 平台id */
9
+ readonly platform: string;
10
+ /** 直播间号 */
11
+ readonly id: number;
12
+ /** 直播间room_id */
13
+ roomid: number;
14
+ /** 直播信息 */
15
+ live: LiveInfo;
16
+ cover: string;
17
+ /** 主播信息 */
18
+ anchor: UserInfo;
19
+ /** 直播间是否可用 */
20
+ available: boolean;
21
+ /** 直播间弹幕api模块 */
22
+ client: KeepLiveWS | null;
23
+ /** 是否为持续监听状态 */
24
+ opening: boolean;
25
+ /** 断线重连间隔 */
26
+ connectInterval: number;
27
+ constructor(id: number, // 房间id
28
+ open?: boolean, // 生成房间后是否打开
29
+ config?: {
30
+ connectInterval: number;
31
+ });
32
+ /** 获取房间信息 */
33
+ getInfo(): Promise<void>;
34
+ /** 开启直播间监听 */
35
+ open(): Promise<void>;
36
+ /** 连接直播服务端 */
37
+ createWS(): Promise<void>;
38
+ close(): void;
39
+ destory(): void;
40
+ emitMsg(data: any): void;
41
+ emitOrigin(data: any): void;
42
+ getDanmakuMode(n: number): string;
43
+ /** 获取弹幕消息 */
44
+ msg_DANMU_MSG(msg: any): void;
45
+ /** 获取互动消息 */
46
+ msg_INTERACT_WORD(msg: any): void;
47
+ /** 获取礼物消息 */
48
+ msg_SEND_GIFT(msg: any): void;
49
+ /** 获取舰长开通消息 */
50
+ msg_GUARD_BUY(msg: any): void;
51
+ /** 获取醒目留言消息 */
52
+ msg_SUPER_CHAT_MESSAGE(msg: any): void;
53
+ msg_ROOM_BLOCK_MSG(msg: any): void;
54
+ msg_LIVE(msg: any): void;
55
+ msg_CUT_OFF(msg: any): void;
56
+ msg_PREPARING(msg: any): void;
57
+ }
58
+ export default bilibiliLive;