Lib.core.OnebotAPI

OnebotAPI 可以方便的调用Onebot的API

  1#   __  __       ____       _         ____        _   _____
  2#  |  \/  |_   _|  _ \ __ _(_)_ __   | __ )  ___ | |_|___  \
  3#  | |\/| | | | | |_) / _` | | '_ \  |  _ \ / _ \| __| __) |
  4#  | |  | | |_| |  _ < (_| | | | | | | |_) | (_) | |_ / __/
  5#  |_|  |_|\__,_|_| \_\__,_|_|_| |_| |____/ \___/ \__|_____|
  6
  7"""
  8OnebotAPI
  9可以方便的调用Onebot的API
 10"""
 11
 12import json
 13import traceback
 14import urllib.parse
 15import requests
 16
 17from . import EventManager, ConfigManager
 18from ..common import save_exc_dump
 19from ..utils import Logger
 20
 21logger = Logger.get_logger()
 22config = ConfigManager.GlobalConfig()
 23
 24
 25class CallAPIEvent(EventManager.Event):
 26    """
 27    调用API事件
 28    """
 29    def __init__(self, full_path, node, data):
 30        self.full_path: str = full_path
 31        self.node: str = node
 32        self.data: dict | None = data
 33
 34
 35class OnebotAPI:
 36    """
 37    OnebotAPI
 38    """
 39    def __init__(self, host: str = None, port: int = None,
 40                 original: bool = False):
 41        """
 42        Args:
 43            host: 调用的ip
 44            port: 调用的端口
 45            original: 是否返回全部json(默认只返回data内)
 46        """
 47        if host is None:
 48            host = config.api.host
 49        if port is None:
 50            port = config.api.port
 51
 52        self.host = host
 53        self.port = port
 54        self.original = original
 55
 56    def set_url(self, host: str, port: int):
 57        """
 58        设置url
 59        Args:
 60            host: 请求的host
 61            port: 请求的端口
 62        """
 63        self.host = host
 64        self.port = port
 65
 66    def get(self, node, data: dict = None, original: bool = None):
 67        """
 68        调用api
 69        Args:
 70            node: 节点
 71            data: 数据
 72            original: 是否返回全部json(默认只返回data内)
 73        """
 74
 75        if original is None:
 76            original = self.original
 77
 78        if node == "":
 79            raise ValueError('The node cannot be empty.')
 80
 81        host = self.host
 82        port = self.port
 83
 84        if not host:
 85            raise ValueError('The host cannot be empty.')
 86
 87        if (not isinstance(port, int)) or port > 65535 or port < 0:
 88            raise ValueError('The port cannot be empty.')
 89
 90        if not (host.startswith("http://") or host.startswith("https://")):
 91            host = "http://" + host
 92
 93        # 拼接url
 94        url = urllib.parse.urljoin(host + ":" + str(port), node)
 95
 96        # 广播call_api事件
 97        event = CallAPIEvent(url, node, data)
 98        event.call_async()
 99        if traceback.extract_stack()[-1].filename == traceback.extract_stack()[-2].filename:
100            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-3].filename}")
101        else:
102            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-2].filename}")
103        headers = {
104                    "Content-Type": "application/json"
105        }
106        if config.api.access_token:
107            headers["Authorization"] = f"Bearer {config.api.access_token}"
108        # 发起get请求
109        creat_dump = True
110        try:
111            response = requests.post(
112                url,
113                headers=headers,
114                data=json.dumps(data if data is not None else {})
115            )
116            if response.status_code != 200 or (response.json()['status'] != 'ok' or response.json()['retcode'] != 0):
117                creat_dump = False
118                raise Exception(f"返回异常, 状态码: {response.status_code}, 返回内容: {response.text}")
119
120            # 如果original为真,则返回原值和response
121            if original:
122                return response.json()
123            else:
124                return response.json()['data']
125        except Exception as e:
126            if ConfigManager.GlobalConfig().debug.save_dump and creat_dump:
127                dump_path = save_exc_dump(f"调用 API: {node} data: {data} 异常")
128            else:
129                dump_path = None
130            logger.error(
131                f"调用 API: {node} data: {data} 异常: {repr(e)}\n"
132                f"{traceback.format_exc()}"
133                f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}"
134            )
135            raise e
136
137    def send_private_msg(self, user_id: int, message: str | list[dict]):
138        """
139        发送私聊消息
140        Args:
141            user_id: 用户id
142            message: 消息内容
143        """
144        data = {
145            "user_id": user_id,
146            "message": message
147        }
148        return self.get("/send_private_msg", data)
149
150    def send_group_msg(self, group_id: int, message: str | list[dict]):
151        """
152        发送群消息
153        Args:
154            group_id: 群号
155            message: 消息内容
156        """
157        data = {
158            "group_id": group_id,
159            "message": message
160        }
161        return self.get("/send_group_msg", data)
162
163    def send_msg(self, user_id: int = -1, group_id: int = -1, message: str | list[dict] = ""):
164        """
165        发送消息
166        Args:
167            user_id: 用户id
168            group_id: 群号
169            message: 消息内容
170        """
171        if user_id != -1 and group_id != -1:
172            raise ValueError('user_id and group_id cannot be both not -1.')
173        if user_id == -1 and group_id == -1:
174            raise ValueError('user_id and group_id cannot be both -1.')
175        if user_id != -1:
176            return self.send_private_msg(user_id, message)
177        elif group_id != -1:
178            return self.send_group_msg(group_id, message)
179        else:
180            raise ValueError('user_id and group_id cannot be both -1.')
181
182    def delete_msg(self, message_id: int):
183        """
184        删除消息
185        Args:
186            message_id: 消息id
187        """
188        data = {
189            "message_id": message_id
190        }
191        return self.get("/delete_msg", data)
192
193    def get_msg(self, message_id: int):
194        """
195        获取消息
196        Args:
197            message_id: 消息id
198        """
199        data = {
200            "message_id": message_id
201        }
202        return self.get("/get_msg", data)
203
204    def get_forward_msg(self, id: int):
205        """
206        获取合并转发消息
207        Args:
208            id: 合并转发id
209        """
210        data = {
211            "id": id
212        }
213        return self.get("/get_forward_msg", data)
214
215    def send_like(self, user_id: int, times: int = 1):
216        """
217        发送点赞
218        Args:
219            user_id: 用户id
220            times: 点赞次数
221        """
222        data = {
223            "user_id": user_id,
224            "times": times
225        }
226        return self.get("/send_like", data)
227
228    def set_group_kick(self, group_id: int, user_id: int, reject_add_request: bool = False):
229        """
230        群组踢人
231        Args:
232            group_id: 群号
233            user_id: 用户id
234            reject_add_request: 拒绝加群请求
235        """
236        data = {
237            "group_id": group_id,
238            "user_id": user_id,
239            "reject_add_request": reject_add_request
240        }
241        return self.get("/set_group_kick", data)
242
243    def set_group_ban(self, group_id: int, user_id: int, duration: int = 30 * 60):
244        """
245        群组单人禁言
246        Args:
247            group_id: 群号
248            user_id: 用户id
249            duration: 禁言时长,单位秒,0 表示取消禁言
250        """
251        data = {
252            "group_id": group_id,
253            "user_id": user_id,
254            "duration": duration
255        }
256        return self.get("/set_group_ban", data)
257
258    def set_group_anonymous_ban(self, group_id: int, anonymous: dict, duration: int = 30 * 60):
259        """
260        群组匿名用户禁言
261        Args:
262            group_id: 群号
263            anonymous: 匿名用户对象
264            duration: 禁言时长,单位秒,无法取消禁言
265        """
266        data = {
267            "group_id": group_id,
268            "anonymous": anonymous,
269            "duration": duration
270        }
271        return self.get("/set_group_anonymous_ban", data)
272
273    def set_group_whole_ban(self, group_id: int, enable: bool = True):
274        """
275        群组全员禁言
276        Args:
277            group_id: 群号
278            enable: 是否禁言
279        """
280        data = {
281            "group_id": group_id,
282            "enable": enable
283        }
284        return self.get("/set_group_whole_ban", data)
285
286    def set_group_admin(self, group_id: int, user_id: int, enable: bool = True):
287        """
288        群组设置管理员
289        Args:
290            group_id: 群号
291            user_id: 用户id
292            enable: 是否设置管理员
293        """
294        data = {
295            "group_id": group_id,
296            "user_id": user_id,
297            "enable": enable
298        }
299        return self.get("/set_group_admin", data)
300
301    def set_group_card(self, group_id: int, user_id: int, card: str = ""):
302        """
303        设置群名片(群备注)
304        Args:
305            group_id: 群号
306            user_id: 用户id
307            card: 群名片内容
308        """
309        data = {
310            "group_id": group_id,
311            "user_id": user_id,
312            "card": card
313        }
314        return self.get("/set_group_card", data)
315
316    def set_group_name(self, group_id: int, group_name: str):
317        """
318        设置群名
319        Args:
320            group_id: 群号
321            group_name: 群名
322        """
323        data = {
324            "group_id": group_id,
325            "group_name": group_name
326        }
327        return self.get("/set_group_name", data)
328
329    def set_group_leave(self, group_id: int, is_dismiss: bool = False):
330        """
331        Args:
332            group_id: 群号
333            is_dismiss: 是否解散,如果登录号是群主,则仅在此项为True时能够解散
334        """
335        data = {
336            "group_id": group_id,
337            "is_dismiss": is_dismiss
338        }
339        return self.get("/set_group_leave", data)
340
341    def set_group_special_title(self, group_id: int, user_id: int, special_title: str = "", duration: int = -1):
342        """
343        设置群组专属头衔
344        Args:
345            group_id: 群号
346            user_id: 要设置的QQ号
347            special_title: 专属头衔,不填或空字符串表示删除专属头衔
348            duration: 专属头衔有效期,-1表示永久,其他值表示在此时间之前专属头衔会消失
349        """
350        data = {
351            "group_id": group_id,
352            "user_id": user_id,
353            "special_title": special_title,
354        }
355        if duration != -1:
356            data["duration"] = duration
357
358        return self.get("/set_group_special_title", data)
359
360    def set_friend_add_request(self, flag: str, approve: bool = True, remark: str = ""):
361        """
362        设置好友添加请求
363        Args:
364            flag: 请求flag
365            approve: 是否同意请求
366            remark: 添加后的好友备注
367        """
368        data = {
369            "flag": flag,
370            "approve": approve,
371            "remark": remark
372        }
373        return self.get("/set_friend_add_request", data)
374
375    def set_group_add_request(self, flag: str, sub_type: str = "add", approve: bool = True, reason: str = ""):
376        """
377        设置群添加请求
378        Args:
379            flag: 请求flag
380            sub_type: 添加请求类型,请参考api文档
381            approve: 是否同意请求
382            reason: 拒绝理由
383        """
384        data = {
385            "flag": flag,
386            "sub_type": sub_type,
387            "approve": approve,
388            "reason": reason
389        }
390        return self.get("/set_group_add_request", data)
391
392    def get_login_info(self):
393        """
394        获取登录号信息
395        """
396        return self.get("/get_login_info")
397
398    def get_stranger_info(self, user_id: int, no_cache: bool = False):
399        """
400        获取陌生人信息
401        Args:
402            user_id: 对方QQ号
403            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
404        """
405        data = {
406            "user_id": user_id,
407            "no_cache": no_cache
408        }
409        return self.get("/get_stranger_info", data)
410
411    def get_friend_list(self):
412        """
413        获取好友列表
414        """
415        return self.get("/get_friend_list")
416
417    def get_group_info(self, group_id: int, no_cache: bool = False):
418        """
419        获取群信息
420        Args:
421            group_id: 群号
422            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
423        """
424        data = {
425            "group_id": group_id,
426            "no_cache": no_cache
427        }
428        return self.get("/get_group_info", data)
429
430    def get_group_list(self):
431        """
432        获取群列表
433        """
434        return self.get("/get_group_list")
435
436    def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False):
437        """
438        获取群成员信息
439        Args:
440            group_id: 群号
441            user_id: QQ号
442            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
443        """
444        data = {
445            "group_id": group_id,
446            "user_id": user_id,
447            "no_cache": no_cache
448        }
449        return self.get("/get_group_member_info", data)
450
451    def get_group_member_list(self, group_id: int):
452        """
453        获取群成员列表
454        Args:
455            group_id: 群号
456        """
457        data = {
458            "group_id": group_id
459        }
460        return self.get("/get_group_member_list", data)
461
462    def get_group_honor_info(self, group_id: int, type_: str = "all"):
463        """
464        获取群荣誉信息
465        Args:
466            group_id: 群号
467            type_: 要获取的群荣誉类型,可传入 talkative performer legend strong_newbie emotion 以分别获取单个类型的群荣誉数据,或传入 all 获取所有数据
468        """
469        data = {
470            "group_id": group_id,
471            "type": type_
472        }
473        return self.get("/get_group_honor_info", data)
474
475    def get_cookies(self):
476        """
477        获取Cookies
478        """
479        return self.get("/get_cookies")
480
481    def get_csrf_token(self):
482        """
483        获取CSRF Token
484        """
485        return self.get("/get_csrf_token")
486
487    def get_credentials(self):
488        """
489        获取Credentials
490        """
491        return self.get("/get_credentials")
492
493    def get_record(self, file: str, out_format: str = "mp3", out_file: str = ""):
494        """
495        获取语音
496        Args:
497            file: 文件ID
498            out_format: 输出格式,mp3或amr,默认mp3
499            out_file: 输出文件名,默认使用文件ID
500        """
501        data = {
502            "file": file,
503            "out_format": out_format,
504            "out_file": out_file
505        }
506        return self.get("/get_record", data)
507
508    def get_image(self, file: str):
509        """
510        获取图片
511        Args:
512            file: 文件ID
513        """
514        data = {
515            "file": file
516        }
517        return self.get("/get_image", data)
518
519    def can_send_image(self):
520        """
521        检查是否可以发送图片
522        """
523        return self.get("/can_send_image")
524
525    def can_send_record(self):
526        """
527        检查是否可以发送语音
528        """
529        return self.get("/can_send_record")
530
531    def get_status(self):
532        """
533        获取运行状态
534        """
535        return self.get("/get_status")
536
537    def get_version_info(self):
538        """
539        获取版本信息
540        """
541        return self.get("/get_version_info")
542
543    def set_restart(self, delay: int = 0):
544        """
545        重启OneBot
546        Args:
547            delay: 延迟时间,单位秒,默认0
548        """
549        data = {
550            "delay": delay
551        }
552        return self.get("/set_restart", data)
553
554    def clean_cache(self):
555        """
556        清理缓存
557        """
558        return self.get("/clean_cache")
559
560
561api = OnebotAPI()
logger = <RootLogger root (INFO)>
class CallAPIEvent(Lib.core.EventManager.Event):
26class CallAPIEvent(EventManager.Event):
27    """
28    调用API事件
29    """
30    def __init__(self, full_path, node, data):
31        self.full_path: str = full_path
32        self.node: str = node
33        self.data: dict | None = data

调用API事件

CallAPIEvent(full_path, node, data)
30    def __init__(self, full_path, node, data):
31        self.full_path: str = full_path
32        self.node: str = node
33        self.data: dict | None = data
full_path: str
node: str
data: dict | None
class OnebotAPI:
 36class OnebotAPI:
 37    """
 38    OnebotAPI
 39    """
 40    def __init__(self, host: str = None, port: int = None,
 41                 original: bool = False):
 42        """
 43        Args:
 44            host: 调用的ip
 45            port: 调用的端口
 46            original: 是否返回全部json(默认只返回data内)
 47        """
 48        if host is None:
 49            host = config.api.host
 50        if port is None:
 51            port = config.api.port
 52
 53        self.host = host
 54        self.port = port
 55        self.original = original
 56
 57    def set_url(self, host: str, port: int):
 58        """
 59        设置url
 60        Args:
 61            host: 请求的host
 62            port: 请求的端口
 63        """
 64        self.host = host
 65        self.port = port
 66
 67    def get(self, node, data: dict = None, original: bool = None):
 68        """
 69        调用api
 70        Args:
 71            node: 节点
 72            data: 数据
 73            original: 是否返回全部json(默认只返回data内)
 74        """
 75
 76        if original is None:
 77            original = self.original
 78
 79        if node == "":
 80            raise ValueError('The node cannot be empty.')
 81
 82        host = self.host
 83        port = self.port
 84
 85        if not host:
 86            raise ValueError('The host cannot be empty.')
 87
 88        if (not isinstance(port, int)) or port > 65535 or port < 0:
 89            raise ValueError('The port cannot be empty.')
 90
 91        if not (host.startswith("http://") or host.startswith("https://")):
 92            host = "http://" + host
 93
 94        # 拼接url
 95        url = urllib.parse.urljoin(host + ":" + str(port), node)
 96
 97        # 广播call_api事件
 98        event = CallAPIEvent(url, node, data)
 99        event.call_async()
100        if traceback.extract_stack()[-1].filename == traceback.extract_stack()[-2].filename:
101            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-3].filename}")
102        else:
103            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-2].filename}")
104        headers = {
105                    "Content-Type": "application/json"
106        }
107        if config.api.access_token:
108            headers["Authorization"] = f"Bearer {config.api.access_token}"
109        # 发起get请求
110        creat_dump = True
111        try:
112            response = requests.post(
113                url,
114                headers=headers,
115                data=json.dumps(data if data is not None else {})
116            )
117            if response.status_code != 200 or (response.json()['status'] != 'ok' or response.json()['retcode'] != 0):
118                creat_dump = False
119                raise Exception(f"返回异常, 状态码: {response.status_code}, 返回内容: {response.text}")
120
121            # 如果original为真,则返回原值和response
122            if original:
123                return response.json()
124            else:
125                return response.json()['data']
126        except Exception as e:
127            if ConfigManager.GlobalConfig().debug.save_dump and creat_dump:
128                dump_path = save_exc_dump(f"调用 API: {node} data: {data} 异常")
129            else:
130                dump_path = None
131            logger.error(
132                f"调用 API: {node} data: {data} 异常: {repr(e)}\n"
133                f"{traceback.format_exc()}"
134                f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}"
135            )
136            raise e
137
138    def send_private_msg(self, user_id: int, message: str | list[dict]):
139        """
140        发送私聊消息
141        Args:
142            user_id: 用户id
143            message: 消息内容
144        """
145        data = {
146            "user_id": user_id,
147            "message": message
148        }
149        return self.get("/send_private_msg", data)
150
151    def send_group_msg(self, group_id: int, message: str | list[dict]):
152        """
153        发送群消息
154        Args:
155            group_id: 群号
156            message: 消息内容
157        """
158        data = {
159            "group_id": group_id,
160            "message": message
161        }
162        return self.get("/send_group_msg", data)
163
164    def send_msg(self, user_id: int = -1, group_id: int = -1, message: str | list[dict] = ""):
165        """
166        发送消息
167        Args:
168            user_id: 用户id
169            group_id: 群号
170            message: 消息内容
171        """
172        if user_id != -1 and group_id != -1:
173            raise ValueError('user_id and group_id cannot be both not -1.')
174        if user_id == -1 and group_id == -1:
175            raise ValueError('user_id and group_id cannot be both -1.')
176        if user_id != -1:
177            return self.send_private_msg(user_id, message)
178        elif group_id != -1:
179            return self.send_group_msg(group_id, message)
180        else:
181            raise ValueError('user_id and group_id cannot be both -1.')
182
183    def delete_msg(self, message_id: int):
184        """
185        删除消息
186        Args:
187            message_id: 消息id
188        """
189        data = {
190            "message_id": message_id
191        }
192        return self.get("/delete_msg", data)
193
194    def get_msg(self, message_id: int):
195        """
196        获取消息
197        Args:
198            message_id: 消息id
199        """
200        data = {
201            "message_id": message_id
202        }
203        return self.get("/get_msg", data)
204
205    def get_forward_msg(self, id: int):
206        """
207        获取合并转发消息
208        Args:
209            id: 合并转发id
210        """
211        data = {
212            "id": id
213        }
214        return self.get("/get_forward_msg", data)
215
216    def send_like(self, user_id: int, times: int = 1):
217        """
218        发送点赞
219        Args:
220            user_id: 用户id
221            times: 点赞次数
222        """
223        data = {
224            "user_id": user_id,
225            "times": times
226        }
227        return self.get("/send_like", data)
228
229    def set_group_kick(self, group_id: int, user_id: int, reject_add_request: bool = False):
230        """
231        群组踢人
232        Args:
233            group_id: 群号
234            user_id: 用户id
235            reject_add_request: 拒绝加群请求
236        """
237        data = {
238            "group_id": group_id,
239            "user_id": user_id,
240            "reject_add_request": reject_add_request
241        }
242        return self.get("/set_group_kick", data)
243
244    def set_group_ban(self, group_id: int, user_id: int, duration: int = 30 * 60):
245        """
246        群组单人禁言
247        Args:
248            group_id: 群号
249            user_id: 用户id
250            duration: 禁言时长,单位秒,0 表示取消禁言
251        """
252        data = {
253            "group_id": group_id,
254            "user_id": user_id,
255            "duration": duration
256        }
257        return self.get("/set_group_ban", data)
258
259    def set_group_anonymous_ban(self, group_id: int, anonymous: dict, duration: int = 30 * 60):
260        """
261        群组匿名用户禁言
262        Args:
263            group_id: 群号
264            anonymous: 匿名用户对象
265            duration: 禁言时长,单位秒,无法取消禁言
266        """
267        data = {
268            "group_id": group_id,
269            "anonymous": anonymous,
270            "duration": duration
271        }
272        return self.get("/set_group_anonymous_ban", data)
273
274    def set_group_whole_ban(self, group_id: int, enable: bool = True):
275        """
276        群组全员禁言
277        Args:
278            group_id: 群号
279            enable: 是否禁言
280        """
281        data = {
282            "group_id": group_id,
283            "enable": enable
284        }
285        return self.get("/set_group_whole_ban", data)
286
287    def set_group_admin(self, group_id: int, user_id: int, enable: bool = True):
288        """
289        群组设置管理员
290        Args:
291            group_id: 群号
292            user_id: 用户id
293            enable: 是否设置管理员
294        """
295        data = {
296            "group_id": group_id,
297            "user_id": user_id,
298            "enable": enable
299        }
300        return self.get("/set_group_admin", data)
301
302    def set_group_card(self, group_id: int, user_id: int, card: str = ""):
303        """
304        设置群名片(群备注)
305        Args:
306            group_id: 群号
307            user_id: 用户id
308            card: 群名片内容
309        """
310        data = {
311            "group_id": group_id,
312            "user_id": user_id,
313            "card": card
314        }
315        return self.get("/set_group_card", data)
316
317    def set_group_name(self, group_id: int, group_name: str):
318        """
319        设置群名
320        Args:
321            group_id: 群号
322            group_name: 群名
323        """
324        data = {
325            "group_id": group_id,
326            "group_name": group_name
327        }
328        return self.get("/set_group_name", data)
329
330    def set_group_leave(self, group_id: int, is_dismiss: bool = False):
331        """
332        Args:
333            group_id: 群号
334            is_dismiss: 是否解散,如果登录号是群主,则仅在此项为True时能够解散
335        """
336        data = {
337            "group_id": group_id,
338            "is_dismiss": is_dismiss
339        }
340        return self.get("/set_group_leave", data)
341
342    def set_group_special_title(self, group_id: int, user_id: int, special_title: str = "", duration: int = -1):
343        """
344        设置群组专属头衔
345        Args:
346            group_id: 群号
347            user_id: 要设置的QQ号
348            special_title: 专属头衔,不填或空字符串表示删除专属头衔
349            duration: 专属头衔有效期,-1表示永久,其他值表示在此时间之前专属头衔会消失
350        """
351        data = {
352            "group_id": group_id,
353            "user_id": user_id,
354            "special_title": special_title,
355        }
356        if duration != -1:
357            data["duration"] = duration
358
359        return self.get("/set_group_special_title", data)
360
361    def set_friend_add_request(self, flag: str, approve: bool = True, remark: str = ""):
362        """
363        设置好友添加请求
364        Args:
365            flag: 请求flag
366            approve: 是否同意请求
367            remark: 添加后的好友备注
368        """
369        data = {
370            "flag": flag,
371            "approve": approve,
372            "remark": remark
373        }
374        return self.get("/set_friend_add_request", data)
375
376    def set_group_add_request(self, flag: str, sub_type: str = "add", approve: bool = True, reason: str = ""):
377        """
378        设置群添加请求
379        Args:
380            flag: 请求flag
381            sub_type: 添加请求类型,请参考api文档
382            approve: 是否同意请求
383            reason: 拒绝理由
384        """
385        data = {
386            "flag": flag,
387            "sub_type": sub_type,
388            "approve": approve,
389            "reason": reason
390        }
391        return self.get("/set_group_add_request", data)
392
393    def get_login_info(self):
394        """
395        获取登录号信息
396        """
397        return self.get("/get_login_info")
398
399    def get_stranger_info(self, user_id: int, no_cache: bool = False):
400        """
401        获取陌生人信息
402        Args:
403            user_id: 对方QQ号
404            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
405        """
406        data = {
407            "user_id": user_id,
408            "no_cache": no_cache
409        }
410        return self.get("/get_stranger_info", data)
411
412    def get_friend_list(self):
413        """
414        获取好友列表
415        """
416        return self.get("/get_friend_list")
417
418    def get_group_info(self, group_id: int, no_cache: bool = False):
419        """
420        获取群信息
421        Args:
422            group_id: 群号
423            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
424        """
425        data = {
426            "group_id": group_id,
427            "no_cache": no_cache
428        }
429        return self.get("/get_group_info", data)
430
431    def get_group_list(self):
432        """
433        获取群列表
434        """
435        return self.get("/get_group_list")
436
437    def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False):
438        """
439        获取群成员信息
440        Args:
441            group_id: 群号
442            user_id: QQ号
443            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
444        """
445        data = {
446            "group_id": group_id,
447            "user_id": user_id,
448            "no_cache": no_cache
449        }
450        return self.get("/get_group_member_info", data)
451
452    def get_group_member_list(self, group_id: int):
453        """
454        获取群成员列表
455        Args:
456            group_id: 群号
457        """
458        data = {
459            "group_id": group_id
460        }
461        return self.get("/get_group_member_list", data)
462
463    def get_group_honor_info(self, group_id: int, type_: str = "all"):
464        """
465        获取群荣誉信息
466        Args:
467            group_id: 群号
468            type_: 要获取的群荣誉类型,可传入 talkative performer legend strong_newbie emotion 以分别获取单个类型的群荣誉数据,或传入 all 获取所有数据
469        """
470        data = {
471            "group_id": group_id,
472            "type": type_
473        }
474        return self.get("/get_group_honor_info", data)
475
476    def get_cookies(self):
477        """
478        获取Cookies
479        """
480        return self.get("/get_cookies")
481
482    def get_csrf_token(self):
483        """
484        获取CSRF Token
485        """
486        return self.get("/get_csrf_token")
487
488    def get_credentials(self):
489        """
490        获取Credentials
491        """
492        return self.get("/get_credentials")
493
494    def get_record(self, file: str, out_format: str = "mp3", out_file: str = ""):
495        """
496        获取语音
497        Args:
498            file: 文件ID
499            out_format: 输出格式,mp3或amr,默认mp3
500            out_file: 输出文件名,默认使用文件ID
501        """
502        data = {
503            "file": file,
504            "out_format": out_format,
505            "out_file": out_file
506        }
507        return self.get("/get_record", data)
508
509    def get_image(self, file: str):
510        """
511        获取图片
512        Args:
513            file: 文件ID
514        """
515        data = {
516            "file": file
517        }
518        return self.get("/get_image", data)
519
520    def can_send_image(self):
521        """
522        检查是否可以发送图片
523        """
524        return self.get("/can_send_image")
525
526    def can_send_record(self):
527        """
528        检查是否可以发送语音
529        """
530        return self.get("/can_send_record")
531
532    def get_status(self):
533        """
534        获取运行状态
535        """
536        return self.get("/get_status")
537
538    def get_version_info(self):
539        """
540        获取版本信息
541        """
542        return self.get("/get_version_info")
543
544    def set_restart(self, delay: int = 0):
545        """
546        重启OneBot
547        Args:
548            delay: 延迟时间,单位秒,默认0
549        """
550        data = {
551            "delay": delay
552        }
553        return self.get("/set_restart", data)
554
555    def clean_cache(self):
556        """
557        清理缓存
558        """
559        return self.get("/clean_cache")

OnebotAPI

OnebotAPI(host: str = None, port: int = None, original: bool = False)
40    def __init__(self, host: str = None, port: int = None,
41                 original: bool = False):
42        """
43        Args:
44            host: 调用的ip
45            port: 调用的端口
46            original: 是否返回全部json(默认只返回data内)
47        """
48        if host is None:
49            host = config.api.host
50        if port is None:
51            port = config.api.port
52
53        self.host = host
54        self.port = port
55        self.original = original
Arguments:
  • host: 调用的ip
  • port: 调用的端口
  • original: 是否返回全部json(默认只返回data内)
host
port
original
def set_url(self, host: str, port: int):
57    def set_url(self, host: str, port: int):
58        """
59        设置url
60        Args:
61            host: 请求的host
62            port: 请求的端口
63        """
64        self.host = host
65        self.port = port

设置url

Arguments:
  • host: 请求的host
  • port: 请求的端口
def get(self, node, data: dict = None, original: bool = None):
 67    def get(self, node, data: dict = None, original: bool = None):
 68        """
 69        调用api
 70        Args:
 71            node: 节点
 72            data: 数据
 73            original: 是否返回全部json(默认只返回data内)
 74        """
 75
 76        if original is None:
 77            original = self.original
 78
 79        if node == "":
 80            raise ValueError('The node cannot be empty.')
 81
 82        host = self.host
 83        port = self.port
 84
 85        if not host:
 86            raise ValueError('The host cannot be empty.')
 87
 88        if (not isinstance(port, int)) or port > 65535 or port < 0:
 89            raise ValueError('The port cannot be empty.')
 90
 91        if not (host.startswith("http://") or host.startswith("https://")):
 92            host = "http://" + host
 93
 94        # 拼接url
 95        url = urllib.parse.urljoin(host + ":" + str(port), node)
 96
 97        # 广播call_api事件
 98        event = CallAPIEvent(url, node, data)
 99        event.call_async()
100        if traceback.extract_stack()[-1].filename == traceback.extract_stack()[-2].filename:
101            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-3].filename}")
102        else:
103            logger.debug(f"调用 API: {node} data: {data} by: {traceback.extract_stack()[-2].filename}")
104        headers = {
105                    "Content-Type": "application/json"
106        }
107        if config.api.access_token:
108            headers["Authorization"] = f"Bearer {config.api.access_token}"
109        # 发起get请求
110        creat_dump = True
111        try:
112            response = requests.post(
113                url,
114                headers=headers,
115                data=json.dumps(data if data is not None else {})
116            )
117            if response.status_code != 200 or (response.json()['status'] != 'ok' or response.json()['retcode'] != 0):
118                creat_dump = False
119                raise Exception(f"返回异常, 状态码: {response.status_code}, 返回内容: {response.text}")
120
121            # 如果original为真,则返回原值和response
122            if original:
123                return response.json()
124            else:
125                return response.json()['data']
126        except Exception as e:
127            if ConfigManager.GlobalConfig().debug.save_dump and creat_dump:
128                dump_path = save_exc_dump(f"调用 API: {node} data: {data} 异常")
129            else:
130                dump_path = None
131            logger.error(
132                f"调用 API: {node} data: {data} 异常: {repr(e)}\n"
133                f"{traceback.format_exc()}"
134                f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}"
135            )
136            raise e

调用api

Arguments:
  • node: 节点
  • data: 数据
  • original: 是否返回全部json(默认只返回data内)
def send_private_msg(self, user_id: int, message: str | list[dict]):
138    def send_private_msg(self, user_id: int, message: str | list[dict]):
139        """
140        发送私聊消息
141        Args:
142            user_id: 用户id
143            message: 消息内容
144        """
145        data = {
146            "user_id": user_id,
147            "message": message
148        }
149        return self.get("/send_private_msg", data)

发送私聊消息

Arguments:
  • user_id: 用户id
  • message: 消息内容
def send_group_msg(self, group_id: int, message: str | list[dict]):
151    def send_group_msg(self, group_id: int, message: str | list[dict]):
152        """
153        发送群消息
154        Args:
155            group_id: 群号
156            message: 消息内容
157        """
158        data = {
159            "group_id": group_id,
160            "message": message
161        }
162        return self.get("/send_group_msg", data)

发送群消息

Arguments:
  • group_id: 群号
  • message: 消息内容
def send_msg( self, user_id: int = -1, group_id: int = -1, message: str | list[dict] = ''):
164    def send_msg(self, user_id: int = -1, group_id: int = -1, message: str | list[dict] = ""):
165        """
166        发送消息
167        Args:
168            user_id: 用户id
169            group_id: 群号
170            message: 消息内容
171        """
172        if user_id != -1 and group_id != -1:
173            raise ValueError('user_id and group_id cannot be both not -1.')
174        if user_id == -1 and group_id == -1:
175            raise ValueError('user_id and group_id cannot be both -1.')
176        if user_id != -1:
177            return self.send_private_msg(user_id, message)
178        elif group_id != -1:
179            return self.send_group_msg(group_id, message)
180        else:
181            raise ValueError('user_id and group_id cannot be both -1.')

发送消息

Arguments:
  • user_id: 用户id
  • group_id: 群号
  • message: 消息内容
def delete_msg(self, message_id: int):
183    def delete_msg(self, message_id: int):
184        """
185        删除消息
186        Args:
187            message_id: 消息id
188        """
189        data = {
190            "message_id": message_id
191        }
192        return self.get("/delete_msg", data)

删除消息

Arguments:
  • message_id: 消息id
def get_msg(self, message_id: int):
194    def get_msg(self, message_id: int):
195        """
196        获取消息
197        Args:
198            message_id: 消息id
199        """
200        data = {
201            "message_id": message_id
202        }
203        return self.get("/get_msg", data)

获取消息

Arguments:
  • message_id: 消息id
def get_forward_msg(self, id: int):
205    def get_forward_msg(self, id: int):
206        """
207        获取合并转发消息
208        Args:
209            id: 合并转发id
210        """
211        data = {
212            "id": id
213        }
214        return self.get("/get_forward_msg", data)

获取合并转发消息

Arguments:
  • id: 合并转发id
def send_like(self, user_id: int, times: int = 1):
216    def send_like(self, user_id: int, times: int = 1):
217        """
218        发送点赞
219        Args:
220            user_id: 用户id
221            times: 点赞次数
222        """
223        data = {
224            "user_id": user_id,
225            "times": times
226        }
227        return self.get("/send_like", data)

发送点赞

Arguments:
  • user_id: 用户id
  • times: 点赞次数
def set_group_kick(self, group_id: int, user_id: int, reject_add_request: bool = False):
229    def set_group_kick(self, group_id: int, user_id: int, reject_add_request: bool = False):
230        """
231        群组踢人
232        Args:
233            group_id: 群号
234            user_id: 用户id
235            reject_add_request: 拒绝加群请求
236        """
237        data = {
238            "group_id": group_id,
239            "user_id": user_id,
240            "reject_add_request": reject_add_request
241        }
242        return self.get("/set_group_kick", data)

群组踢人

Arguments:
  • group_id: 群号
  • user_id: 用户id
  • reject_add_request: 拒绝加群请求
def set_group_ban(self, group_id: int, user_id: int, duration: int = 1800):
244    def set_group_ban(self, group_id: int, user_id: int, duration: int = 30 * 60):
245        """
246        群组单人禁言
247        Args:
248            group_id: 群号
249            user_id: 用户id
250            duration: 禁言时长,单位秒,0 表示取消禁言
251        """
252        data = {
253            "group_id": group_id,
254            "user_id": user_id,
255            "duration": duration
256        }
257        return self.get("/set_group_ban", data)

群组单人禁言

Arguments:
  • group_id: 群号
  • user_id: 用户id
  • duration: 禁言时长,单位秒,0 表示取消禁言
def set_group_anonymous_ban(self, group_id: int, anonymous: dict, duration: int = 1800):
259    def set_group_anonymous_ban(self, group_id: int, anonymous: dict, duration: int = 30 * 60):
260        """
261        群组匿名用户禁言
262        Args:
263            group_id: 群号
264            anonymous: 匿名用户对象
265            duration: 禁言时长,单位秒,无法取消禁言
266        """
267        data = {
268            "group_id": group_id,
269            "anonymous": anonymous,
270            "duration": duration
271        }
272        return self.get("/set_group_anonymous_ban", data)

群组匿名用户禁言

Arguments:
  • group_id: 群号
  • anonymous: 匿名用户对象
  • duration: 禁言时长,单位秒,无法取消禁言
def set_group_whole_ban(self, group_id: int, enable: bool = True):
274    def set_group_whole_ban(self, group_id: int, enable: bool = True):
275        """
276        群组全员禁言
277        Args:
278            group_id: 群号
279            enable: 是否禁言
280        """
281        data = {
282            "group_id": group_id,
283            "enable": enable
284        }
285        return self.get("/set_group_whole_ban", data)

群组全员禁言

Arguments:
  • group_id: 群号
  • enable: 是否禁言
def set_group_admin(self, group_id: int, user_id: int, enable: bool = True):
287    def set_group_admin(self, group_id: int, user_id: int, enable: bool = True):
288        """
289        群组设置管理员
290        Args:
291            group_id: 群号
292            user_id: 用户id
293            enable: 是否设置管理员
294        """
295        data = {
296            "group_id": group_id,
297            "user_id": user_id,
298            "enable": enable
299        }
300        return self.get("/set_group_admin", data)

群组设置管理员

Arguments:
  • group_id: 群号
  • user_id: 用户id
  • enable: 是否设置管理员
def set_group_card(self, group_id: int, user_id: int, card: str = ''):
302    def set_group_card(self, group_id: int, user_id: int, card: str = ""):
303        """
304        设置群名片(群备注)
305        Args:
306            group_id: 群号
307            user_id: 用户id
308            card: 群名片内容
309        """
310        data = {
311            "group_id": group_id,
312            "user_id": user_id,
313            "card": card
314        }
315        return self.get("/set_group_card", data)

设置群名片(群备注)

Arguments:
  • group_id: 群号
  • user_id: 用户id
  • card: 群名片内容
def set_group_name(self, group_id: int, group_name: str):
317    def set_group_name(self, group_id: int, group_name: str):
318        """
319        设置群名
320        Args:
321            group_id: 群号
322            group_name: 群名
323        """
324        data = {
325            "group_id": group_id,
326            "group_name": group_name
327        }
328        return self.get("/set_group_name", data)

设置群名

Arguments:
  • group_id: 群号
  • group_name: 群名
def set_group_leave(self, group_id: int, is_dismiss: bool = False):
330    def set_group_leave(self, group_id: int, is_dismiss: bool = False):
331        """
332        Args:
333            group_id: 群号
334            is_dismiss: 是否解散,如果登录号是群主,则仅在此项为True时能够解散
335        """
336        data = {
337            "group_id": group_id,
338            "is_dismiss": is_dismiss
339        }
340        return self.get("/set_group_leave", data)
Arguments:
  • group_id: 群号
  • is_dismiss: 是否解散,如果登录号是群主,则仅在此项为True时能够解散
def set_group_special_title( self, group_id: int, user_id: int, special_title: str = '', duration: int = -1):
342    def set_group_special_title(self, group_id: int, user_id: int, special_title: str = "", duration: int = -1):
343        """
344        设置群组专属头衔
345        Args:
346            group_id: 群号
347            user_id: 要设置的QQ号
348            special_title: 专属头衔,不填或空字符串表示删除专属头衔
349            duration: 专属头衔有效期,-1表示永久,其他值表示在此时间之前专属头衔会消失
350        """
351        data = {
352            "group_id": group_id,
353            "user_id": user_id,
354            "special_title": special_title,
355        }
356        if duration != -1:
357            data["duration"] = duration
358
359        return self.get("/set_group_special_title", data)

设置群组专属头衔

Arguments:
  • group_id: 群号
  • user_id: 要设置的QQ号
  • special_title: 专属头衔,不填或空字符串表示删除专属头衔
  • duration: 专属头衔有效期,-1表示永久,其他值表示在此时间之前专属头衔会消失
def set_friend_add_request(self, flag: str, approve: bool = True, remark: str = ''):
361    def set_friend_add_request(self, flag: str, approve: bool = True, remark: str = ""):
362        """
363        设置好友添加请求
364        Args:
365            flag: 请求flag
366            approve: 是否同意请求
367            remark: 添加后的好友备注
368        """
369        data = {
370            "flag": flag,
371            "approve": approve,
372            "remark": remark
373        }
374        return self.get("/set_friend_add_request", data)

设置好友添加请求

Arguments:
  • flag: 请求flag
  • approve: 是否同意请求
  • remark: 添加后的好友备注
def set_group_add_request( self, flag: str, sub_type: str = 'add', approve: bool = True, reason: str = ''):
376    def set_group_add_request(self, flag: str, sub_type: str = "add", approve: bool = True, reason: str = ""):
377        """
378        设置群添加请求
379        Args:
380            flag: 请求flag
381            sub_type: 添加请求类型,请参考api文档
382            approve: 是否同意请求
383            reason: 拒绝理由
384        """
385        data = {
386            "flag": flag,
387            "sub_type": sub_type,
388            "approve": approve,
389            "reason": reason
390        }
391        return self.get("/set_group_add_request", data)

设置群添加请求

Arguments:
  • flag: 请求flag
  • sub_type: 添加请求类型,请参考api文档
  • approve: 是否同意请求
  • reason: 拒绝理由
def get_login_info(self):
393    def get_login_info(self):
394        """
395        获取登录号信息
396        """
397        return self.get("/get_login_info")

获取登录号信息

def get_stranger_info(self, user_id: int, no_cache: bool = False):
399    def get_stranger_info(self, user_id: int, no_cache: bool = False):
400        """
401        获取陌生人信息
402        Args:
403            user_id: 对方QQ号
404            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
405        """
406        data = {
407            "user_id": user_id,
408            "no_cache": no_cache
409        }
410        return self.get("/get_stranger_info", data)

获取陌生人信息

Arguments:
  • user_id: 对方QQ号
  • no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
def get_friend_list(self):
412    def get_friend_list(self):
413        """
414        获取好友列表
415        """
416        return self.get("/get_friend_list")

获取好友列表

def get_group_info(self, group_id: int, no_cache: bool = False):
418    def get_group_info(self, group_id: int, no_cache: bool = False):
419        """
420        获取群信息
421        Args:
422            group_id: 群号
423            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
424        """
425        data = {
426            "group_id": group_id,
427            "no_cache": no_cache
428        }
429        return self.get("/get_group_info", data)

获取群信息

Arguments:
  • group_id: 群号
  • no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
def get_group_list(self):
431    def get_group_list(self):
432        """
433        获取群列表
434        """
435        return self.get("/get_group_list")

获取群列表

def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False):
437    def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False):
438        """
439        获取群成员信息
440        Args:
441            group_id: 群号
442            user_id: QQ号
443            no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
444        """
445        data = {
446            "group_id": group_id,
447            "user_id": user_id,
448            "no_cache": no_cache
449        }
450        return self.get("/get_group_member_info", data)

获取群成员信息

Arguments:
  • group_id: 群号
  • user_id: QQ号
  • no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
def get_group_member_list(self, group_id: int):
452    def get_group_member_list(self, group_id: int):
453        """
454        获取群成员列表
455        Args:
456            group_id: 群号
457        """
458        data = {
459            "group_id": group_id
460        }
461        return self.get("/get_group_member_list", data)

获取群成员列表

Arguments:
  • group_id: 群号
def get_group_honor_info(self, group_id: int, type_: str = 'all'):
463    def get_group_honor_info(self, group_id: int, type_: str = "all"):
464        """
465        获取群荣誉信息
466        Args:
467            group_id: 群号
468            type_: 要获取的群荣誉类型,可传入 talkative performer legend strong_newbie emotion 以分别获取单个类型的群荣誉数据,或传入 all 获取所有数据
469        """
470        data = {
471            "group_id": group_id,
472            "type": type_
473        }
474        return self.get("/get_group_honor_info", data)

获取群荣誉信息

Arguments:
  • group_id: 群号
  • type_: 要获取的群荣誉类型,可传入 talkative performer legend strong_newbie emotion 以分别获取单个类型的群荣誉数据,或传入 all 获取所有数据
def get_cookies(self):
476    def get_cookies(self):
477        """
478        获取Cookies
479        """
480        return self.get("/get_cookies")

获取Cookies

def get_csrf_token(self):
482    def get_csrf_token(self):
483        """
484        获取CSRF Token
485        """
486        return self.get("/get_csrf_token")

获取CSRF Token

def get_credentials(self):
488    def get_credentials(self):
489        """
490        获取Credentials
491        """
492        return self.get("/get_credentials")

获取Credentials

def get_record(self, file: str, out_format: str = 'mp3', out_file: str = ''):
494    def get_record(self, file: str, out_format: str = "mp3", out_file: str = ""):
495        """
496        获取语音
497        Args:
498            file: 文件ID
499            out_format: 输出格式,mp3或amr,默认mp3
500            out_file: 输出文件名,默认使用文件ID
501        """
502        data = {
503            "file": file,
504            "out_format": out_format,
505            "out_file": out_file
506        }
507        return self.get("/get_record", data)

获取语音

Arguments:
  • file: 文件ID
  • out_format: 输出格式,mp3或amr,默认mp3
  • out_file: 输出文件名,默认使用文件ID
def get_image(self, file: str):
509    def get_image(self, file: str):
510        """
511        获取图片
512        Args:
513            file: 文件ID
514        """
515        data = {
516            "file": file
517        }
518        return self.get("/get_image", data)

获取图片

Arguments:
  • file: 文件ID
def can_send_image(self):
520    def can_send_image(self):
521        """
522        检查是否可以发送图片
523        """
524        return self.get("/can_send_image")

检查是否可以发送图片

def can_send_record(self):
526    def can_send_record(self):
527        """
528        检查是否可以发送语音
529        """
530        return self.get("/can_send_record")

检查是否可以发送语音

def get_status(self):
532    def get_status(self):
533        """
534        获取运行状态
535        """
536        return self.get("/get_status")

获取运行状态

def get_version_info(self):
538    def get_version_info(self):
539        """
540        获取版本信息
541        """
542        return self.get("/get_version_info")

获取版本信息

def set_restart(self, delay: int = 0):
544    def set_restart(self, delay: int = 0):
545        """
546        重启OneBot
547        Args:
548            delay: 延迟时间,单位秒,默认0
549        """
550        data = {
551            "delay": delay
552        }
553        return self.get("/set_restart", data)

重启OneBot

Arguments:
  • delay: 延迟时间,单位秒,默认0
def clean_cache(self):
555    def clean_cache(self):
556        """
557        清理缓存
558        """
559        return self.get("/clean_cache")

清理缓存

api = <OnebotAPI object>