floating-live 0.17.0-alpha.13 → 0.17.0-alpha.15

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/LICENSE CHANGED
@@ -1,9 +1,9 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Minteea
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Minteea
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
9
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,36 +1,36 @@
1
- # Floating Live
2
-
3
- 一个用于处理和保存直播弹幕的 Web 小工具,开箱即用。
4
-
5
- 本体无弹幕获取功能,需要配合[floating-live-plugins](https://github.com/Minteea/floating-live-plugins)中的插件使用。
6
-
7
- 目前插件库支持 bilibili 和 AcFun 的直播弹幕,不同平台的弹幕会转换为同一种格式便于保存。
8
-
9
- 项目仍在开发中,功能尚未完善,目前除了记录保存直播弹幕外暂时没有别的用处啦,敬请期待。
10
-
11
- 注意:当前项目未进入正式版本阶段,程序结构及导出数据结构可能随时改动,**非常不建议用于正式项目中**。
12
-
13
- GUI 版本:[Minteea/floating-live-gui](https://github.com/Minteea/floating-live-gui)
14
-
15
- ## 使用方法
16
-
17
- ### npm 安装
18
-
19
- ```
20
- npm install floating-live
21
- ```
22
-
23
- ```javascript
24
- // 导入FloatingLive本体
25
- import { FloatingLive } from "floating-live";
26
- // 导入bilibili房间生成插件
27
- import bilibili from "@floating-live/bilibili";
28
-
29
- // 创建一个FloatingLive实例
30
- const live = new FloatingLive();
31
- // 注册插件
32
- live.plugin.register(bilibili);
33
-
34
- // 添加房间并自动打开
35
- live.room.add("bilibili", 6, true);
36
- ```
1
+ # Floating Live
2
+
3
+ 一个用于处理和保存直播弹幕的 Web 小工具,开箱即用。
4
+
5
+ 本体无弹幕获取功能,需要配合[floating-live-plugins](https://github.com/Minteea/floating-live-plugins)中的插件使用。
6
+
7
+ 目前插件库支持 bilibili 和 AcFun 的直播弹幕,不同平台的弹幕会转换为同一种格式便于保存。
8
+
9
+ 项目仍在开发中,功能尚未完善,目前除了记录保存直播弹幕外暂时没有别的用处啦,敬请期待。
10
+
11
+ 注意:当前项目未进入正式版本阶段,程序结构及导出数据结构可能随时改动,**非常不建议用于正式项目中**。
12
+
13
+ GUI 版本:[Minteea/floating-live-gui](https://github.com/Minteea/floating-live-gui)
14
+
15
+ ## 使用方法
16
+
17
+ ### npm 安装
18
+
19
+ ```
20
+ npm install floating-live
21
+ ```
22
+
23
+ ```javascript
24
+ // 导入FloatingLive本体
25
+ import { FloatingLive } from "floating-live";
26
+ // 导入bilibili房间生成插件
27
+ import bilibili from "@floating-live/bilibili";
28
+
29
+ // 创建一个FloatingLive实例
30
+ const live = new FloatingLive();
31
+ // 注册插件
32
+ live.plugin.register(bilibili);
33
+
34
+ // 添加房间并自动打开
35
+ live.room.add("bilibili", 6, true);
36
+ ```
@@ -1,4 +1,9 @@
1
1
  import { appError } from "../error/index.js";
2
+ // 错误列表
3
+ // command:notFound 命令不存在
4
+ // command:alreadyExists 命令已存在
5
+ // command:aliasNotFound 命令别名指向的命令不存在
6
+ // command:aliasTargetUncallable 命令别名不可指向其他命令别名
2
7
  export class CommandManager {
3
8
  /** 功能列表 */
4
9
  list = new Map();
@@ -31,9 +36,10 @@ export class CommandManager {
31
36
  callWithOptions(name, options, ...args) {
32
37
  const command = this.list.get(name);
33
38
  if (!command) {
34
- throw appError("command:call_unexist", {
39
+ throw appError("command:notFound", {
35
40
  message: `命令不存在[${name}]`,
36
41
  target: `command/${name}`,
42
+ action: "command.call",
37
43
  });
38
44
  }
39
45
  else {
@@ -50,17 +56,19 @@ export class CommandManager {
50
56
  _callAliasWithOptions(name, targetName, options, ...args) {
51
57
  const tcommand = this.list.get(targetName);
52
58
  if (!tcommand) {
53
- throw appError("command:alias_unexist", {
59
+ throw appError("command:aliasNotFound", {
54
60
  message: `命令别名[${name}]指向的命令不存在[${targetName}]`,
55
61
  target: `command/${name}>${targetName}`,
62
+ action: "command.call",
56
63
  });
57
64
  }
58
65
  else {
59
66
  const { call } = tcommand;
60
67
  if (!call) {
61
- throw appError("command:alias_target_uncallable", {
68
+ throw appError("command:aliasTargetUncallable", {
62
69
  message: `命令别名[${name}]不可指向其他命令别名[${targetName}]`,
63
70
  target: `command/${name}>${targetName}>${tcommand.targetName}`,
71
+ action: "command.call",
64
72
  });
65
73
  }
66
74
  return call({ source: options.source, client: options.client }, ...args);
@@ -8,6 +8,8 @@ export interface AppError extends Error {
8
8
  target?: string;
9
9
  /** 错误原因 */
10
10
  reason?: string | Error | AppError;
11
+ /** 调用行为 */
12
+ action?: string;
11
13
  };
12
14
  }
13
15
  export interface AppErrorOptions {
@@ -17,8 +19,10 @@ export interface AppErrorOptions {
17
19
  target?: string;
18
20
  /** 错误原因 */
19
21
  reason?: string | Error | AppError;
22
+ /** 调用行为 */
23
+ action?: string;
20
24
  /** 错误构造函数 */
21
25
  errorConstructor?: ErrorConstructor;
22
26
  [key: string]: unknown;
23
27
  }
24
- export declare function appError(code: string, { message, target, reason, errorConstructor }: AppErrorOptions): AppError;
28
+ export declare function appError(code: string, { message, target, reason, action, errorConstructor, }: AppErrorOptions): AppError;
@@ -1,10 +1,14 @@
1
1
  export * from "./types.js";
2
- export function appError(code, { message, target, reason, errorConstructor = Error }) {
2
+ export function appError(code, { message, target, reason, action, errorConstructor = Error, }) {
3
3
  return new errorConstructor(message, {
4
4
  cause: {
5
5
  code,
6
6
  target,
7
7
  reason,
8
+ action,
8
9
  },
9
10
  });
10
11
  }
12
+ // 错误码分类
13
+ // http:xxx http状态码
14
+ // node:xxx nodejs错误码
@@ -1,4 +1,7 @@
1
1
  import { appError } from "../error/index.js";
2
+ // 错误列表
3
+ // hook:functionAlreadyExists 钩子函数已存在
4
+ // hook:functionNotFound 钩子函数不存在
2
5
  export class HookManager {
3
6
  list = new Map();
4
7
  pluginMap = new Map();
@@ -16,10 +19,10 @@ export class HookManager {
16
19
  this.list.set(name, hooks);
17
20
  }
18
21
  else if (hooks.includes(call)) {
19
- throw appError("hook:use_duplicate", {
20
- message: `钩子函数挂载失败: ${name}`,
21
- reason: "重复挂载同一函数",
22
+ throw appError("hook:functionAlreadyExists", {
23
+ message: `无法重复挂载同一钩子函数: ${name}`,
22
24
  target: `hook/${name}`,
25
+ action: "hook.use",
23
26
  });
24
27
  }
25
28
  hooks.push({ call, pluginName });
@@ -29,10 +32,10 @@ export class HookManager {
29
32
  let hooks = this.list.get(name);
30
33
  const index = hooks?.findIndex((item) => item.call == call) ?? -1;
31
34
  if (!hooks || index < 0)
32
- throw appError("hook:unuse_unexist", {
33
- message: `钩子函数卸载失败: ${name}`,
34
- reason: "卸载不存在的钩子函数",
35
+ throw appError("hook:functionNotFound", {
36
+ message: `无法卸载不存在的钩子函数: ${name}`,
35
37
  target: `hook/${name}`,
38
+ action: "hook.unuse",
36
39
  });
37
40
  hooks.splice(index, 1);
38
41
  }
@@ -1,5 +1,7 @@
1
1
  import { DanmakuMode, UserInfo, ImageInfo, GiftInfo, UserType } from "./messageInfo.js";
2
2
  import { LiveRoomStatus, LiveRoomStatsInfo, LiveRoomDetailInfo } from "./room.js";
3
+ export interface LiveMessageExtensions {
4
+ }
3
5
  export declare namespace LiveMessage {
4
6
  interface Base {
5
7
  /** 平台名称 */
@@ -12,15 +14,22 @@ export declare namespace LiveMessage {
12
14
  type: string;
13
15
  /** 时间戳 */
14
16
  timestamp: number;
15
- /** 消息id */
17
+ /** 消息id
18
+ *
19
+ * 须保证不重复性,规范id格式如下:
20
+ *
21
+ * 用户相关消息:platform:roomId-type:userId-uniqueId
22
+ *
23
+ * 房间相关消息:platform:roomId-type-uniqueId
24
+ * */
16
25
  id: string;
17
- /** 其他属性 */
18
- [attr: string]: any;
26
+ /** 拓展属性 */
27
+ extension?: LiveMessageExtensions;
19
28
  }
20
29
  /** 聊天消息 */
21
30
  interface Comment extends Base {
22
31
  type: "comment";
23
- info: {
32
+ data: {
24
33
  /** 用户信息 */
25
34
  user: UserInfo;
26
35
  /** 文本内容 */
@@ -44,7 +53,7 @@ export declare namespace LiveMessage {
44
53
  /** 礼物消息 */
45
54
  interface Gift extends Base {
46
55
  type: "gift";
47
- info: {
56
+ data: {
48
57
  /** 用户信息 */
49
58
  user: UserInfo;
50
59
  /** 礼物信息 */
@@ -54,7 +63,7 @@ export declare namespace LiveMessage {
54
63
  /** 互动消息(进入直播间、点赞、关注、分享、加入粉丝团) */
55
64
  interface Interact extends Base {
56
65
  type: "entry" | "like" | "follow" | "share" | "join";
57
- info: {
66
+ data: {
58
67
  /** 用户信息 */
59
68
  user: UserInfo;
60
69
  /** 信息标签 */
@@ -64,7 +73,7 @@ export declare namespace LiveMessage {
64
73
  /** 粉丝vip开通消息 */
65
74
  interface Membership extends Base {
66
75
  type: "membership";
67
- info: {
76
+ data: {
68
77
  /** 用户信息 */
69
78
  user: UserInfo;
70
79
  /** 礼物信息 */
@@ -77,12 +86,12 @@ export declare namespace LiveMessage {
77
86
  duration: number;
78
87
  };
79
88
  }
80
- /** 粉丝vip开通消息 */
89
+ /** 付费留言消息 */
81
90
  interface Superchat extends Base {
82
91
  type: "superchat";
83
- info: {
84
- /** 留言id */
85
- id: string | number;
92
+ data: {
93
+ /** 留言代码,用于撤回消息 */
94
+ token: string | number;
86
95
  /** 用户信息 */
87
96
  user: UserInfo;
88
97
  /** 文本内容 */
@@ -95,10 +104,17 @@ export declare namespace LiveMessage {
95
104
  duration: number;
96
105
  };
97
106
  }
107
+ /** 付费留言删除消息 */
108
+ interface SuperchatDelete extends Base {
109
+ type: "superchat_delete";
110
+ data: {
111
+ token: string;
112
+ };
113
+ }
98
114
  /** 禁言消息 */
99
115
  interface Block extends Base {
100
116
  type: "block";
101
- info: {
117
+ data: {
102
118
  /** 用户信息 */
103
119
  user: UserInfo;
104
120
  /** 操作者 */
@@ -110,7 +126,7 @@ export declare namespace LiveMessage {
110
126
  /** 直播开播消息 */
111
127
  interface LiveStart extends Base {
112
128
  type: "live_start";
113
- info: {
129
+ data: {
114
130
  /** 直播id */
115
131
  id: string;
116
132
  };
@@ -118,7 +134,7 @@ export declare namespace LiveMessage {
118
134
  /** 直播结束 */
119
135
  interface LiveEnd extends Base {
120
136
  type: "live_end";
121
- info: {
137
+ data: {
122
138
  /** 直播状态 */
123
139
  status: LiveRoomStatus;
124
140
  };
@@ -126,72 +142,21 @@ export declare namespace LiveMessage {
126
142
  /** 直播切断消息 */
127
143
  interface LiveCut extends Base {
128
144
  type: "live_cut";
129
- info: {
145
+ data: {
130
146
  /** 切断消息 */
131
147
  message: string;
148
+ status: LiveRoomStatus;
132
149
  };
133
150
  }
134
151
  /** 直播数据更新 */
135
152
  interface LiveStats extends Base {
136
153
  type: "live_stats";
137
- info: LiveRoomStatsInfo;
154
+ data: LiveRoomStatsInfo;
138
155
  }
139
156
  /** 直播展示信息更新 */
140
157
  interface LiveDetail extends Base {
141
158
  type: "live_detail";
142
- info: LiveRoomDetailInfo;
143
- }
144
- /** 主播抽奖 */
145
- interface Lottery extends Base {
146
- type: "lottery";
147
- info: {
148
- title: string;
149
- role: "user" | "anchor";
150
- user?: UserInfo;
151
- gift?: GiftInfo;
152
- id: string | number;
153
- award?: GiftInfo | GiftInfo[];
154
- value?: number;
155
- valueType?: string | number;
156
- price?: number;
157
- currency?: string;
158
- };
159
- }
160
- /** 主播抽奖结果 */
161
- interface LotteryResult extends Base {
162
- type: "lottery_result";
163
- info: {
164
- title: string;
165
- role: "user" | "anchor";
166
- id: string | number;
167
- result: {
168
- user: UserInfo;
169
- award: GiftInfo | GiftInfo[];
170
- }[];
171
- };
172
- }
173
- /** 发送红包 */
174
- interface Redpacket extends Base {
175
- type: "redpacket";
176
- info: {
177
- id: string | number;
178
- gifts?: GiftInfo[];
179
- value?: number;
180
- currency?: string | number;
181
- };
182
- }
183
- /** 红包抽奖结果 */
184
- interface RedpacketResult extends Base {
185
- type: "redpacket_result";
186
- info: {
187
- id: string | number;
188
- result: {
189
- user: UserInfo;
190
- gift?: GiftInfo;
191
- value?: number;
192
- currency?: string | number;
193
- }[];
194
- };
159
+ data: LiveRoomDetailInfo;
195
160
  }
196
- type All = Comment | Gift | Interact | Membership | Superchat | Block | LiveStart | LiveEnd | LiveCut | LiveDetail | LiveStats | Lottery | LotteryResult;
161
+ type All = Comment | Gift | Interact | Membership | Superchat | Block | LiveStart | LiveEnd | LiveCut | LiveDetail | LiveStats;
197
162
  }
@@ -13,8 +13,8 @@ export interface UserInfo {
13
13
  type?: UserType;
14
14
  /** 粉丝vip等级 */
15
15
  membership?: boolean | number;
16
- /** vip等级 */
17
- vip?: boolean | number;
16
+ /** 平台vip等级 */
17
+ premium?: boolean | number;
18
18
  /** 用户等级 */
19
19
  level?: number;
20
20
  }
@@ -50,18 +50,20 @@ export interface GiftInfo {
50
50
  num: number;
51
51
  /** 礼物价值(总价,按平台货币计算) */
52
52
  value?: number;
53
- /** 价值类型 */
53
+ /** 平台货币类型 */
54
54
  valueType?: string | number;
55
+ /** 显示的平台货币数量 */
56
+ coins?: number;
55
57
  /** 平台货币名称 */
56
- valueName?: string;
57
- /** 礼物连击数 */
58
- combo?: number;
59
- /** 礼物连击id */
60
- comboId?: string;
58
+ coinName?: string;
61
59
  /** 礼物金额(总价,按消费现金计算) */
62
60
  price?: number;
63
61
  /** 礼物金额货币 */
64
62
  currency?: string;
63
+ /** 礼物连击数 */
64
+ combo?: number;
65
+ /** 礼物连击id */
66
+ comboId?: string;
65
67
  /** 行为 */
66
68
  action?: string;
67
69
  /** 随机礼物信息 */
@@ -2,7 +2,7 @@ export interface LivePlatformInfo {
2
2
  /** 平台名称 */
3
3
  name: string;
4
4
  /** 平台vip信息 */
5
- vip?: {
5
+ premium?: {
6
6
  /** 平台vip对应id */
7
7
  id: string;
8
8
  /** 平台vip名称 */
@@ -7,11 +7,10 @@ export declare abstract class LiveRoom extends CustomEventEmitter implements Liv
7
7
  constructor();
8
8
  get valid(): true;
9
9
  get pending(): false;
10
- get service(): string;
11
10
  /** 平台 */
12
11
  abstract readonly platform: string;
13
- /** api服务 */
14
- readonly serviceName: string;
12
+ /** 服务id */
13
+ abstract readonly service: string;
15
14
  /** 房间id */
16
15
  abstract readonly id: string | number;
17
16
  /** 房间详情 */
@@ -61,14 +60,13 @@ export declare abstract class LiveRoom extends CustomEventEmitter implements Liv
61
60
  /** 无效房间 */
62
61
  export declare class InvalidLiveRoom implements LiveRoomData {
63
62
  get valid(): false;
64
- get service(): string;
65
63
  constructor(service: string, id: string | number, { pending, error }?: {
66
64
  pending?: boolean | undefined;
67
65
  error?: null | undefined;
68
66
  });
69
67
  readonly platform: string;
68
+ readonly service: string;
70
69
  readonly id: string | number;
71
- readonly serviceName: string;
72
70
  pending: boolean;
73
71
  detail: LiveRoomDetailInfo;
74
72
  stats?: LiveRoomStatsInfo;
@@ -100,15 +98,13 @@ export interface LiveRoomData {
100
98
  /** 房间有效性 */
101
99
  valid: boolean;
102
100
  /** 房间待定状态 */
103
- pending: boolean;
101
+ pending?: boolean;
104
102
  /** 平台id */
105
103
  platform: string;
106
- /** API服务 */
107
- serviceName: string;
104
+ /** 服务id */
105
+ service: string;
108
106
  /** 房间id */
109
107
  id: number | string;
110
- /** API服务id */
111
- service: string;
112
108
  /** 房间key */
113
109
  key: string;
114
110
  /** 基本信息 */
@@ -156,6 +152,10 @@ export interface LiveRoomStatsInfo {
156
152
  online?: number;
157
153
  /** 人气值 */
158
154
  popularity?: number;
155
+ /** 粉丝数 */
156
+ fans?: number;
157
+ /** 粉丝团人数 */
158
+ clubFans?: number;
159
159
  }
160
160
  /** 直播间状态 */
161
161
  export declare const LiveRoomStatus: {
package/dist/live/room.js CHANGED
@@ -10,13 +10,6 @@ export class LiveRoom extends CustomEventEmitter {
10
10
  get pending() {
11
11
  return false;
12
12
  }
13
- get service() {
14
- return this.serviceName
15
- ? `${this.platform}.${this.serviceName}`
16
- : this.platform;
17
- }
18
- /** api服务 */
19
- serviceName = "";
20
13
  /** 统计信息 */
21
14
  stats;
22
15
  /** 直播状态 */
@@ -53,24 +46,24 @@ export class LiveRoom extends CustomEventEmitter {
53
46
  this.emit("status", {
54
47
  status: LiveRoomStatus.live,
55
48
  timestamp: msg.timestamp,
56
- liveId: msg.info.id,
49
+ liveId: msg.data.id,
57
50
  });
58
51
  break;
59
52
  case "live_detail":
60
- this.detail = Object.assign(this.detail, msg.info);
61
- this.emit("detail", { detail: msg.info });
53
+ this.detail = Object.assign(this.detail, msg.data);
54
+ this.emit("detail", { detail: msg.data });
62
55
  break;
63
56
  case "live_stats":
64
- this.stats = Object.assign(this.stats, msg.info);
65
- this.emit("stats", { stats: msg.info });
57
+ this.stats = Object.assign(this.stats, msg.data);
58
+ this.emit("stats", { stats: msg.data });
66
59
  break;
67
60
  case "live_end":
68
61
  case "live_cut":
69
- this.status = msg.status || LiveRoomStatus.off;
62
+ this.status = msg.data.status || LiveRoomStatus.off;
70
63
  this.timestamp = msg.timestamp;
71
64
  this.emit("message", { message: msg });
72
65
  this.emit("status", {
73
- status: msg.status || LiveRoomStatus.off,
66
+ status: msg.data.status || LiveRoomStatus.off,
74
67
  timestamp: msg.timestamp,
75
68
  liveId: this.liveId,
76
69
  });
@@ -88,7 +81,6 @@ export class LiveRoom extends CustomEventEmitter {
88
81
  valid: this.valid,
89
82
  pending: this.pending,
90
83
  platform: this.platform,
91
- serviceName: this.serviceName,
92
84
  id: this.id,
93
85
  detail: this.detail,
94
86
  stats: this.stats,
@@ -113,22 +105,17 @@ export class InvalidLiveRoom {
113
105
  get valid() {
114
106
  return false;
115
107
  }
116
- get service() {
117
- return this.serviceName
118
- ? `${this.platform}.${this.serviceName}`
119
- : this.platform;
120
- }
121
108
  constructor(service, id, { pending = false, error = null } = {}) {
122
- const [platform, ...serviceIdArr] = service.split(".");
109
+ const [platform] = service.split(".");
123
110
  this.platform = platform;
124
111
  this.id = id;
125
- this.serviceName = serviceIdArr.join(".");
112
+ this.service = service;
126
113
  this.pending = pending;
127
114
  this.error = error;
128
115
  }
129
116
  platform;
117
+ service;
130
118
  id;
131
- serviceName;
132
119
  pending;
133
120
  detail = {};
134
121
  stats;
@@ -149,7 +136,7 @@ export class InvalidLiveRoom {
149
136
  valid: this.valid,
150
137
  pending: this.pending,
151
138
  platform: this.platform,
152
- serviceName: this.serviceName,
139
+ service: this.service,
153
140
  id: this.id,
154
141
  detail: this.detail,
155
142
  stats: this.stats,
@@ -161,7 +148,6 @@ export class InvalidLiveRoom {
161
148
  opened: this.opened,
162
149
  available: this.available,
163
150
  connectionStatus: this.connectionStatus,
164
- service: this.service,
165
151
  key: this.key,
166
152
  };
167
153
  }
@@ -1,5 +1,7 @@
1
1
  import { appError } from "../../error/index.js";
2
2
  import { CommonPluginContext } from "./CommonPluginContext.js";
3
+ // 错误列表
4
+ // plugin:noPermission 插件权限不足
3
5
  export class SafePluginContext extends CommonPluginContext {
4
6
  get safe() {
5
7
  return true;
@@ -10,7 +12,7 @@ export class SafePluginContext extends CommonPluginContext {
10
12
  this.#permissions = options.permissions;
11
13
  }
12
14
  throwNotPermitted(permission, reason) {
13
- throw appError("plugin:no_permission", {
15
+ throw appError("plugin:noPermission", {
14
16
  message: "插件权限不足",
15
17
  reason,
16
18
  permission,
@@ -1,6 +1,13 @@
1
1
  import { CommonPluginContext } from "./context/CommonPluginContext.js";
2
2
  import { bindCommand } from "../utils/index.js";
3
3
  import { appError } from "../error/index.js";
4
+ // 错误列表
5
+ // plugin:missingName 插件pluginName字段缺失
6
+ // plugin:duplicateName 已存在相同名称的插件
7
+ // plugin:unremovable 插件不可移除
8
+ // plugin:registerFailed 插件注册失败
9
+ // plugin:notFound 插件不存在
10
+ // app:hookPrevented 被钩子函数阻止
4
11
  export class PluginManager {
5
12
  /** 插件列表 */
6
13
  list = new Map();
@@ -14,15 +21,17 @@ export class PluginManager {
14
21
  const pluginName = pluginConstructor.pluginName;
15
22
  const role = pluginConstructor.role || "";
16
23
  if (!pluginName) {
17
- throw appError("plugin:register_id_missing", {
24
+ throw appError("plugin:missingName", {
18
25
  message: "插件注册失败: 插件缺少pluginName字段",
19
26
  target: "plugin/#unnamed",
27
+ action: "plugin.registerSync",
20
28
  });
21
29
  }
22
30
  if (this.list.has(pluginName)) {
23
- throw appError("plugin:register_id_duplicate", {
24
- message: `插件注册失败[${pluginName}]: 已存在相同id的插件`,
31
+ throw appError("plugin:duplicateName", {
32
+ message: `插件注册失败[${pluginName}]: 已存在相同名称的插件`,
25
33
  target: `plugin/${pluginName}`,
34
+ action: "plugin.registerSync",
26
35
  });
27
36
  }
28
37
  const registerCtx = { pluginName, options };
@@ -30,9 +39,10 @@ export class PluginManager {
30
39
  try {
31
40
  const ctx = this.app.callHookSync("plugin.register", registerCtx);
32
41
  if (ctx.defaultPrevented)
33
- throw appError("plugin:register_hook_prevented", {
42
+ throw appError("app:hookPrevented", {
34
43
  message: `插件注册失败${pluginName}: 插件注册被钩子函数阻止`,
35
44
  target: `plugin/${pluginName}`,
45
+ action: "plugin.registerSync",
36
46
  });
37
47
  // 执行插件函数
38
48
  const plugin = new pluginConstructor(pluginCtx, registerCtx.options || {});
@@ -68,10 +78,11 @@ export class PluginManager {
68
78
  return plugin;
69
79
  }
70
80
  catch (err) {
71
- throw appError("plugin:register_fail", {
81
+ throw appError("plugin:registerFailed", {
72
82
  message: `插件注册失败: ${pluginName}`,
73
83
  reason: err,
74
84
  target: `plugin/${pluginName}`,
85
+ action: "plugin.registerSync",
75
86
  });
76
87
  }
77
88
  }
@@ -80,15 +91,17 @@ export class PluginManager {
80
91
  const pluginName = pluginConstructor.pluginName;
81
92
  const role = pluginConstructor.role || "";
82
93
  if (!pluginName) {
83
- throw appError("plugin:register_id_missing", {
94
+ throw appError("plugin:missingName", {
84
95
  message: "插件注册失败: 插件缺少pluginName字段",
85
96
  target: "plugin/#unnamed",
97
+ action: "plugin.register",
86
98
  });
87
99
  }
88
100
  if (this.list.has(pluginName)) {
89
- throw appError("plugin:register_id_duplicate", {
90
- message: `插件注册失败[${pluginName}]: 已存在相同id的插件`,
101
+ throw appError("plugin:duplicateName", {
102
+ message: `插件注册失败[${pluginName}]: 已存在相同名称的插件`,
91
103
  target: `plugin/${pluginName}`,
104
+ action: "plugin.register",
92
105
  });
93
106
  }
94
107
  const registerCtx = { pluginName, options };
@@ -97,9 +110,10 @@ export class PluginManager {
97
110
  .callHook("plugin.register", registerCtx)
98
111
  .then(async (ctx) => {
99
112
  if (ctx.defaultPrevented)
100
- throw appError("plugin:register_hook_prevented", {
113
+ throw appError("app:hookPrevented", {
101
114
  message: `插件注册失败${pluginName}: 插件注册被钩子函数阻止`,
102
115
  target: `plugin/${pluginName}`,
116
+ action: "plugin.register",
103
117
  });
104
118
  // 执行插件函数
105
119
  const plugin = new pluginConstructor(pluginCtx, registerCtx.options || {});
@@ -134,10 +148,11 @@ export class PluginManager {
134
148
  return plugin;
135
149
  })
136
150
  .catch((err) => {
137
- throw appError("plugin:register_fail", {
151
+ throw appError("plugin:registerFailed", {
138
152
  message: `插件注册失败: ${pluginName}`,
139
153
  reason: err,
140
154
  target: `plugin/${pluginName}`,
155
+ action: "plugin.register",
141
156
  });
142
157
  });
143
158
  }
@@ -146,17 +161,19 @@ export class PluginManager {
146
161
  const pluginData = this.list.get(pluginName);
147
162
  // 检测插件是否存在
148
163
  if (!pluginData) {
149
- throw appError("plugin:unregister_unexist", {
164
+ throw appError("plugin:notFound", {
150
165
  message: `插件移除失败[${pluginName}]: 插件不存在`,
151
166
  target: `plugin/${pluginName}`,
167
+ action: "plugin.unregister",
152
168
  });
153
169
  }
154
170
  else {
155
171
  const { plugin, context, unremovable, role } = pluginData;
156
172
  if (unremovable) {
157
- throw appError("plugin:unregister_unremovable", {
173
+ throw appError("plugin:unremovable", {
158
174
  message: `插件移除失败[${pluginName}]: 该插件已配置为不可移除`,
159
175
  target: `plugin/${pluginName}`,
176
+ action: "plugin.unregister",
160
177
  });
161
178
  }
162
179
  // 调用插件和上下文的destroy钩子
@@ -11,8 +11,10 @@ export class Platform extends BasePlugin {
11
11
  /** 注册直播平台信息 */
12
12
  register(name, info, signal) {
13
13
  if (this.list.has(name)) {
14
- throw appError("platform:register_duplicated", {
15
- message: "平台信息重复注册",
14
+ throw appError("platform:alreadyExists", {
15
+ message: "平台信息已存在",
16
+ target: `platform/${name}`,
17
+ action: "platform.register",
16
18
  });
17
19
  }
18
20
  this.list.set(name, info);
@@ -25,8 +27,10 @@ export class Platform extends BasePlugin {
25
27
  /** 解除注册直播平台信息 */
26
28
  unregister(name) {
27
29
  if (!this.list.has(name)) {
28
- throw appError("platform:unregister_unexisted", {
30
+ throw appError("platform:notFound", {
29
31
  message: "无法解除不存在的平台信息注册",
32
+ target: `platform/${name}`,
33
+ action: "platform.unregister",
30
34
  });
31
35
  }
32
36
  this.list.delete(name);
@@ -49,9 +49,10 @@ export class Room extends BasePlugin {
49
49
  attach(room, open) {
50
50
  const key = room.key;
51
51
  if (this.map.has(key)) {
52
- throw appError("room:add_exist", {
52
+ throw appError("room:alreadyExists", {
53
53
  message: `房间已存在[${key}]`,
54
54
  target: `room/${key}`,
55
+ action: "room.add",
55
56
  });
56
57
  }
57
58
  this.map.set(key, room);
@@ -68,9 +69,10 @@ export class Room extends BasePlugin {
68
69
  detach(key) {
69
70
  const room = this.map.get(key);
70
71
  if (!room) {
71
- throw appError("room:remove_unexist", {
72
+ throw appError("room:notFound", {
72
73
  message: `房间不存在[${key}]`,
73
74
  target: `room/${key}`,
75
+ action: "room.remove",
74
76
  });
75
77
  }
76
78
  this.map.delete(key); // 从表中删除房间
@@ -214,15 +216,18 @@ export class Room extends BasePlugin {
214
216
  const res = await this.ctx
215
217
  .callHook("room.create", ctx)
216
218
  .catch((reason) => {
217
- throw appError("room:create_hook_error", {
219
+ throw appError("app:hookError", {
218
220
  message: `无法创建房间监听实例[${service}:${id}]: 调用钩子函数出错`,
219
221
  target: `room/${service}:${id}`,
222
+ action: "room.create",
223
+ reason,
220
224
  });
221
225
  });
222
226
  if (res.defaultPrevented) {
223
- throw appError("room:create_hook_prevented", {
227
+ throw appError("app:hookPrevented", {
224
228
  message: `无法创建房间监听实例[${service}:${id}]: 房间添加被钩子函数阻止`,
225
229
  target: `room/${service}:${id}`,
230
+ action: "room.create",
226
231
  });
227
232
  }
228
233
  }
@@ -243,10 +248,11 @@ export class Room extends BasePlugin {
243
248
  room = new InvalidLiveRoom(service, id);
244
249
  }
245
250
  else {
246
- throw appError("room:create_fail", {
251
+ throw appError("room:createFailed", {
247
252
  message: `创建房间监听实例失败[${service}:${id}]`,
248
253
  reason: e,
249
254
  target: `room/${service}:${id}`,
255
+ action: "room.create",
250
256
  });
251
257
  }
252
258
  }
@@ -260,10 +266,11 @@ export class Room extends BasePlugin {
260
266
  room.destroy?.();
261
267
  }
262
268
  catch (e) {
263
- throw appError("room:destroy_fail", {
269
+ throw appError("room:destroyFailed", {
264
270
  message: `销毁房间实例失败[${key}]`,
265
271
  reason: e,
266
272
  target: `room/${key}`,
273
+ action: "room.remove",
267
274
  });
268
275
  }
269
276
  }
@@ -272,15 +279,17 @@ export class Room extends BasePlugin {
272
279
  async validate(key, options) {
273
280
  let invalidRoom = this.map.get(key);
274
281
  if (!invalidRoom) {
275
- throw appError("room:validate_unexist", {
282
+ throw appError("room:notFound", {
276
283
  message: `房间不存在[${key}]`,
277
284
  target: `room/${key}`,
285
+ action: "room.validate",
278
286
  });
279
287
  }
280
288
  if (invalidRoom.valid == true) {
281
- throw appError("room:validate_valid", {
289
+ throw appError("room:alreadyValid", {
282
290
  message: `无法使已经有效的房间生效[${key}]`,
283
291
  target: `room/${key}`,
292
+ action: "room.validate",
284
293
  });
285
294
  }
286
295
  const { service, id } = invalidRoom;
@@ -299,15 +308,17 @@ export class Room extends BasePlugin {
299
308
  invalidate(key) {
300
309
  let room = this.map.get(key);
301
310
  if (!room) {
302
- throw appError("room:invalidate_unexist", {
311
+ throw appError("room:notFound", {
303
312
  message: `房间不存在[${key}]`,
304
313
  target: `room/${key}`,
314
+ action: "room.invalidate",
305
315
  });
306
316
  }
307
317
  if (!room.valid) {
308
- throw appError("room:invalidate_invalid", {
318
+ throw appError("room:alreadyInvalid", {
309
319
  message: `无法使已经无效的房间失效[${key}]`,
310
320
  target: `room/${key}`,
321
+ action: "room.invalidate",
311
322
  });
312
323
  }
313
324
  // 用无效房间替换掉原房间
@@ -322,10 +333,11 @@ export class Room extends BasePlugin {
322
333
  room.destroy?.();
323
334
  }
324
335
  catch (e) {
325
- throw appError("room:destroy_fail", {
336
+ throw appError("room:destroyFailed", {
326
337
  message: `销毁房间实例失败[${key}]`,
327
338
  reason: e,
328
339
  target: `room/${key}`,
340
+ action: "room.invalidate",
329
341
  });
330
342
  }
331
343
  }
@@ -358,15 +370,17 @@ export class Room extends BasePlugin {
358
370
  open(key) {
359
371
  let room = this.map.get(key);
360
372
  if (!room) {
361
- throw appError("room:open_unexist", {
373
+ throw appError("room:notFound", {
362
374
  message: "要打开的房间不存在",
363
375
  target: `room/${key}`,
376
+ action: "room.open",
364
377
  });
365
378
  }
366
379
  if (!room.valid) {
367
- throw appError("room:open_invalid", {
380
+ throw appError("room:invalid", {
368
381
  message: "要打开的房间无效",
369
382
  target: `room/${key}`,
383
+ action: "room.open",
370
384
  });
371
385
  }
372
386
  room.open();
@@ -375,15 +389,17 @@ export class Room extends BasePlugin {
375
389
  close(key) {
376
390
  let room = this.map.get(key);
377
391
  if (!room) {
378
- throw appError("room:close_unexist", {
392
+ throw appError("room:notFound", {
379
393
  message: "关闭的房间不存在",
380
394
  target: `room/${key}`,
395
+ action: "room.close",
381
396
  });
382
397
  }
383
398
  if (!room.valid) {
384
- throw appError("room:close_invalid", {
399
+ throw appError("room:invalid", {
385
400
  message: "要关闭的房间无效",
386
401
  target: `room/${key}`,
402
+ action: "room.close",
387
403
  });
388
404
  }
389
405
  room.close();
@@ -393,9 +409,10 @@ export class Room extends BasePlugin {
393
409
  const arr = [...this.map];
394
410
  const index = arr.findIndex(([k]) => k == key);
395
411
  if (index == -1) {
396
- throw appError("room:move_unexist", {
412
+ throw appError("room:notFound", {
397
413
  message: "要移动的房间不存在",
398
414
  target: `room/${key}`,
415
+ action: "room.move",
399
416
  });
400
417
  }
401
418
  const [item] = arr.splice(index, 1);
@@ -408,9 +425,10 @@ export class Room extends BasePlugin {
408
425
  const arr = [...this.map];
409
426
  const index = arr.findIndex(([k]) => k == oldKey);
410
427
  if (index == -1) {
411
- throw appError("room:changekey_unexist", {
428
+ throw appError("room:notFound", {
412
429
  message: "要更改key的房间不存在",
413
430
  target: `room/${oldKey}`,
431
+ action: "room.changeKey",
414
432
  });
415
433
  }
416
434
  let room = arr[index][1];
@@ -1,5 +1,8 @@
1
1
  import { appError } from "../error/index.js";
2
2
  import { bindCommand } from "../utils/index.js";
3
+ // 错误列表
4
+ // value:notFound 值不存在
5
+ // value:alreadyExists 值已存在
3
6
  export class ValueManager {
4
7
  list = new Map();
5
8
  app;
@@ -9,6 +12,13 @@ export class ValueManager {
9
12
  }
10
13
  /** 注册值 */
11
14
  register(name, { get, set, pluginName }) {
15
+ if (this.list.has(name)) {
16
+ throw appError("value:alreadyExists", {
17
+ message: "值已存在",
18
+ target: `value/${name}`,
19
+ action: "value.register",
20
+ });
21
+ }
12
22
  this.list.set(name, { get, set, pluginName });
13
23
  this.app.emit("value:register", { name, value: get() }, { source: `plugin:${pluginName}` });
14
24
  return {
@@ -19,15 +29,26 @@ export class ValueManager {
19
29
  }
20
30
  /** 注销值 */
21
31
  unregister(name) {
22
- this.list.delete(name);
23
- this.app.emit("value:unregister", { name });
32
+ const result = this.list.delete(name);
33
+ if (!result) {
34
+ throw appError("value:notFound", {
35
+ message: "无法注销未注册的值",
36
+ target: `value/${name}`,
37
+ action: "value.unregister",
38
+ });
39
+ }
40
+ else {
41
+ this.app.emit("value:unregister", { name });
42
+ }
24
43
  }
25
44
  /** 获取值 */
26
45
  get(name, options) {
27
46
  const item = this.list.get(name);
28
47
  if (!item)
29
- throw appError("value:get_unexist", {
48
+ throw appError("value:notFound", {
30
49
  message: "无法获取未注册的值",
50
+ target: `value/${name}`,
51
+ action: "value.get",
31
52
  });
32
53
  return item.get(options);
33
54
  }
@@ -39,7 +60,7 @@ export class ValueManager {
39
60
  set(name, value, options) {
40
61
  const valueItem = this.list.get(name);
41
62
  if (valueItem?.set) {
42
- valueItem?.set(value, options);
63
+ valueItem.set(value, options);
43
64
  return true;
44
65
  }
45
66
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floating-live",
3
- "version": "0.17.0-alpha.13",
3
+ "version": "0.17.0-alpha.15",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",