├── .gitignore ├── LICENSE ├── README.md ├── UPDATE.md ├── config.json.example └── push.py /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ColdThunder11 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bilidynamicpush 2 | 一个用于推送哔哩哔哩动态的HoshinoBot插件,支持动态、视频、文章的推送(含图片),支持将6、9宫格图片自动合成单张图片。更新日志可以在[这里](https://github.com/Sora233/bilidynamicpush/blob/main/UPDATE.md)查看。有bug可以在issues中反馈。 3 | ## 使用方法 4 | 将本项目clone至HoshinoBot\hoshino\modules下,将config.json.example重命名为config.json并自行修改所需要订阅的内容,在__bot__.py中加入bilidynamicpush 5 | ## 指令列表 6 | | 指令 | 格式 | 备注 | 7 | | ---------- | -------------- | -------------- | 8 | | 订阅动态 | 订阅动态+空格+需要订阅的UID+空格+需要订阅的群(可选) | 如不输入订阅的群则为当前群,全部群订阅请输入all | 9 | | 取消订阅动态 | 取消订阅动态+空格+需要取消订阅的UID+空格+需要取消订阅的群(可选) | 如不输入取消订阅的群则为当前群,取消全部群订阅请输入all | 10 | | 重新载入动态推送配置 | 无 | 在不重载HoshinoBot的情况下重新载入修改后的配置文件 | 11 | ## 配置文件 12 | 可以直接修改config.json来配置推送设置,message_length_limit为对超长动态和视频简介的字数限制,0为不限制(过长的消息可能会导致风控发送失败)。uid_bind为推送列表字典,key为要推送的uid,value为要推送的群的数组,如果需要全部群推送请修改为\["all"\]。 13 | ## 一些说明 14 | 对于设置为全部推送(all)的情况,插件仅会对启用了该插件的群组进行推送,对于手动指定的群的推送,其推送状态不受插件启用与否的影响,如不需要请自行删除订阅。 15 | ## 支持情况 16 | | 类型 | 17 | | ----- | 18 | | 纯文字动态 √ | 19 | | 带图片动态 √ | 20 | | 转发动态 √ | 21 | | 视频 √ | 22 | | 文章 √ | 23 | | 直播 √ | 24 | | 音频 × | 25 | -------------------------------------------------------------------------------- /UPDATE.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | ### 2021/10/31 3 | 修复:解决b站api更新导致直播推送失效的问题 4 | ### 2021/1/28 5 | 修复:解决了通过命令订阅后会更新时报错keyError的问题 6 | ### 2020/11/26 7 | 修复:修改了获取用户名的方式,缓存了用户名,解决了某些情况下B站返回数据不带用户名导致错误的问题 8 | ### 2020/11/19 9 | 新增:增加了直播状态的订阅 10 | 新增:增加了自动合成6、9宫格的功能 11 | 修复:通过bot命令订阅推送后不会在重新载入前生效的问题 12 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "message_length_limit":150, 3 | "uid_bind":{ 4 | "353840826":["all"] 5 | } 6 | } -------------------------------------------------------------------------------- /push.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import random 4 | import time 5 | import traceback 6 | from os import path 7 | 8 | import nonebot 9 | from PIL import Image 10 | from hoshino import Service 11 | from hoshino import aiorequests 12 | from hoshino.priv import * 13 | 14 | messageLengthLimit = 0 15 | push_uids = {} 16 | push_times = {} 17 | room_states = {} 18 | all_user_name = {} 19 | isOnChecking = False 20 | bilibiliCookie = '' 21 | 22 | sv = Service('bili-dynamic', help_=''' 23 | B站动态推送插件 24 | '''.strip()) 25 | 26 | 27 | async def broadcast(msg, groups=None, sv_name=None): 28 | bot = nonebot.get_bot() 29 | # 当groups指定时,在groups中广播;当groups未指定,但sv_name指定,将在开启该服务的群广播 30 | svs = Service.get_loaded_services() 31 | if not groups and sv_name not in svs: 32 | raise ValueError(f'不存在服务 {sv_name}') 33 | if sv_name: 34 | enable_groups = await svs[sv_name].get_enable_groups() 35 | send_groups = enable_groups.keys() if not groups else groups 36 | else: 37 | send_groups = groups 38 | for gid in send_groups: 39 | try: 40 | await bot.send_group_msg(group_id=gid, message=msg) 41 | await asyncio.sleep(0.5) 42 | except Exception as e: 43 | sv.logger.info(e) 44 | 45 | 46 | def getImageCqCode(path): 47 | return '[CQ:image,file={imgUrl}]'.format(imgUrl=path) 48 | 49 | 50 | def getLimitedMessage(originMsg): 51 | if len(originMsg) > messageLengthLimit > 0: 52 | return originMsg[0:messageLengthLimit] + '……' 53 | else: 54 | return originMsg 55 | 56 | 57 | async def loadConfig(): 58 | global push_uids 59 | global push_times 60 | global room_states 61 | global messageLengthLimit 62 | global bilibiliCookie 63 | push_uids = {} 64 | push_times = {} 65 | room_states = {} 66 | config_path = path.join(path.dirname(__file__), 'config.json') 67 | with open(config_path, 'r', encoding='utf8') as fp: 68 | conf = json.load(fp) 69 | messageLengthLimit = conf['message_length_limit'] 70 | keys = conf['uid_bind'].keys() 71 | for uid in keys: 72 | push_uids[uid] = conf['uid_bind'][uid] 73 | push_times[uid] = int(time.time()) 74 | for uid in keys: 75 | room_states[uid] = False 76 | # 生成16位LIVE_BUVID,好像随机生成没事 77 | list2 = [] 78 | for number in range(16): 79 | str2 = str(random.randint(0, 9)) 80 | list2.append(str2) 81 | b = "".join(list2) 82 | bilibiliCookie = 'LIVE_BUVID=AUTO{random_id};'.format(random_id=b) 83 | await load_all_username() 84 | sv.logger.info('B站动态推送配置文件加载成功') 85 | 86 | 87 | def saveConfig(): 88 | config_path = path.join(path.dirname(__file__), 'config.json') 89 | with open(config_path, 'r+', encoding='utf8') as fp: 90 | conf = json.load(fp) 91 | keys = push_uids.keys() 92 | conf['uid_bind'].clear() 93 | for uid in keys: 94 | conf['uid_bind'][uid] = push_uids[uid] 95 | fp.seek(0) 96 | fp.truncate() 97 | fp.seek(0) 98 | json.dump(conf, fp, indent=4) 99 | 100 | 101 | async def check_uid_exsist(uid): 102 | header = { 103 | 'Referer': 'https://space.bilibili.com/{user_uid}/'.format(user_uid=uid) 104 | } 105 | try: 106 | resp = await aiorequests.get('http://api.bilibili.com/x/space/acc/info?mid={user_uid}'.format(user_uid=uid), headers=header, timeout=20) 107 | res = await resp.json() 108 | if res['code'] == 0: 109 | return True 110 | return False 111 | except Exception as e: 112 | sv.logger.info(f'B站用户检查发生错误 uid={uid}\n' + traceback.format_exc()) 113 | return False 114 | 115 | 116 | async def get_user_name(uid): 117 | header = { 118 | 'Referer': 'https://space.bilibili.com/{user_uid}/'.format(user_uid=uid) 119 | } 120 | try: 121 | resp = await aiorequests.get('http://api.bilibili.com/x/space/acc/info?mid={user_uid}'.format(user_uid=uid), headers=header, timeout=20) 122 | res = await resp.json() 123 | return res['data']['name'] 124 | except Exception as e: 125 | sv.logger.info(f'B站用户名获取发生错误 uid={uid}\n' + traceback.format_exc()) 126 | return False 127 | 128 | 129 | async def load_all_username(): 130 | global all_user_name 131 | uids = push_uids.keys() 132 | for uid in uids: 133 | all_user_name[uid] = await get_user_name(uid) 134 | 135 | 136 | async def load_username(uid): 137 | global all_user_name 138 | if uid not in all_user_name: 139 | all_user_name[uid] = await get_user_name(uid) 140 | 141 | 142 | @sv.on_prefix('订阅动态') 143 | async def subscribe_dynamic(bot, ev): 144 | if push_uids == {}: 145 | await loadConfig() 146 | if not check_priv(ev, SUPERUSER): 147 | await bot.send(ev, '仅有SUPERUSER可以订阅动态') 148 | return 149 | text = str(ev.message).strip() 150 | if not text: 151 | await bot.send(ev, "请按照格式发送", at_sender=True) 152 | return 153 | if not ' ' in text: # 仅当前群组 154 | if not await check_uid_exsist(text): 155 | await bot.send(ev, '订阅失败:用户不存在') 156 | return 157 | if not text in push_uids: 158 | push_uids[text] = [str(ev.group_id)] 159 | room_states[text] = False 160 | else: 161 | if str(ev.group_id) in push_uids[text]: 162 | await bot.send(ev, '订阅失败:请勿重复订阅') 163 | return 164 | push_uids[text].append(str(ev.group_id)) 165 | await load_username(text) 166 | push_times[text] = int(time.time()) 167 | else: 168 | subUid = text.split(' ')[0] 169 | subGroup = text.split(' ')[1] 170 | if not await check_uid_exsist(subUid): 171 | await bot.send(ev, '订阅失败:用户不存在') 172 | return 173 | if not subUid in push_uids: 174 | push_uids[subUid] = [subGroup] 175 | room_states[subUid] = False 176 | else: 177 | if subGroup in push_uids[subUid]: 178 | await bot.send(ev, '订阅失败:请勿重复订阅') 179 | return 180 | push_uids[subUid].append(subGroup) 181 | await load_username(subUid) 182 | push_times[subUid] = int(time.time()) 183 | saveConfig() 184 | await bot.send(ev, '订阅成功') 185 | 186 | 187 | @sv.on_prefix('取消订阅动态') 188 | async def disubscribe_dynamic(bot, ev): 189 | if push_uids == {}: 190 | await loadConfig() 191 | if not check_priv(ev, SUPERUSER): 192 | await bot.send(ev, '仅有SUPERUSER可以取消订阅动态') 193 | return 194 | text = str(ev.message).strip() 195 | if not text: 196 | await bot.send(ev, "请按照格式发送", at_sender=True) 197 | return 198 | if not ' ' in text: # 仅当前群组 199 | sv.logger.info(text) 200 | sv.logger.info(push_uids.keys()) 201 | if text in push_uids.keys(): 202 | if str(ev.group_id) in push_uids[text]: 203 | if len(push_uids[text]) == 1: 204 | push_uids.pop(text) 205 | else: 206 | push_uids[text].remove(str(ev.group_id)) 207 | else: 208 | await bot.send(ev, '取消订阅失败:未找到该订阅') 209 | return 210 | else: 211 | await bot.send(ev, '取消订阅失败:未找到该订阅') 212 | return 213 | else: 214 | subUid = text.split(' ')[0] 215 | subGroup = text.split(' ')[1] 216 | if subGroup == 'all': 217 | if subUid in push_uids: 218 | push_uids.pop(subUid) 219 | else: 220 | await bot.send(ev, '取消订阅失败:未找到该订阅') 221 | return 222 | elif subUid in push_uids: 223 | if subGroup in push_uids[subUid]: 224 | if len(push_uids[subUid]) == 1: 225 | push_uids.pop(subUid) 226 | else: 227 | push_uids[subUid].remove(subGroup) 228 | else: 229 | await bot.send(ev, '取消订阅失败:未找到该订阅') 230 | return 231 | else: 232 | await bot.send(ev, '取消订阅失败:未找到该订阅') 233 | return 234 | saveConfig() 235 | await bot.send(ev, '取消订阅成功') 236 | 237 | 238 | @sv.scheduled_job('cron', minute='*/2') 239 | async def check_bili_dynamic(): 240 | global push_times 241 | global room_states 242 | global isOnChecking 243 | if isOnChecking: 244 | return 245 | isOnChecking = True 246 | if push_uids == {}: 247 | await loadConfig() 248 | uids = push_uids.keys() 249 | sv.logger.info('B站动态检查开始') 250 | for uid in uids: 251 | # if uid != "171818544": 252 | # continue 253 | header = { 254 | 'Referer': 'https://space.bilibili.com/{user_uid}/'.format(user_uid=uid) 255 | } 256 | try: 257 | resp = await aiorequests.get('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?host_uid={user_uid}'.format(user_uid=uid), headers=header, 258 | timeout=20) 259 | res = await resp.json() 260 | if res is None: 261 | sv.logger.info(f'检查{uid}时出错 request response is None') 262 | continue 263 | cards = res['data']['cards'] 264 | # cards=[res['data']['cards'][10]] 265 | uid_time = push_times.get(uid, 0) 266 | push_times[uid] = int(time.time()) 267 | for card in cards: 268 | sendCQCode = [] 269 | userUid = card['desc']['user_profile']['info']['uid'] 270 | # uname=card['desc']['user_profile']['info']['uname'] 271 | uname = all_user_name[uid] 272 | timestamp = card['desc']['timestamp'] 273 | if timestamp < uid_time: 274 | # sv.logger.info(uname+'检查完成') 275 | break 276 | dynamicId = card['desc']['dynamic_id'] 277 | dynamicType = card['desc']['type'] 278 | if dynamicType == 2: # 带图片动态 279 | sendCQCode.append(uname) 280 | sendCQCode.append('发表了动态:\n') 281 | content = card['card'] 282 | contentJo = json.loads(content) 283 | picturesCount = contentJo['item']['pictures_count'] 284 | trueContent = contentJo['item']['description'] 285 | trueContent = getLimitedMessage(trueContent) 286 | sendCQCode.append(trueContent) 287 | pictures = contentJo['item']['pictures'] 288 | if picturesCount > 0: 289 | isBigPicture = False 290 | firstPictureSize = [pictures[0]['img_width'], pictures[0]['img_height']] 291 | if picturesCount >= 9: 292 | isBigPicture = True 293 | for i in range(9): 294 | if pictures[i]['img_width'] != firstPictureSize[0] or pictures[i]['img_height'] != firstPictureSize[1]: 295 | isBigPicture = False 296 | if isBigPicture: 297 | pictureSrcs = [] 298 | for i in range(9): 299 | pictureSrcs.append(pictures[i]['img_src']) 300 | imgPath = await make_big_image(pictureSrcs, firstPictureSize, 9) 301 | sendCQCode.append(getImageCqCode('file:///' + imgPath)) 302 | if picturesCount >= 6 and not isBigPicture: 303 | isBigPicture = True 304 | for i in range(6): 305 | if pictures[i]['img_width'] != firstPictureSize[0] or pictures[i]['img_height'] != firstPictureSize[1]: 306 | isBigPicture = False 307 | if isBigPicture: 308 | pictureSrcs = [] 309 | for i in range(6): 310 | pictureSrcs.append(pictures[i]['img_src']) 311 | imgPath = await make_big_image(pictureSrcs, firstPictureSize, 6) 312 | pictureSrcs = [] 313 | sendCQCode.append(getImageCqCode('file:///' + imgPath)) 314 | if picturesCount > 6: 315 | for i in range(7, picturesCount): 316 | pictureSrcs.append(pictures[i]['img_src']) 317 | for downPic in pictureSrcs: 318 | sendCQCode.append(getImageCqCode(downPic)) 319 | if not isBigPicture: 320 | if picturesCount > 0 and picturesCount < 4: 321 | pictureSrcs = [] 322 | for pic in pictures: 323 | pictureSrcs.append(pic['img_src']) 324 | for downPic in pictureSrcs: 325 | sendCQCode.append(getImageCqCode(downPic)) 326 | sendCQCode.append('\nhttps://t.bilibili.com/{dynamicId}'.format(dynamicId=dynamicId)) 327 | elif dynamicType == 4: # 纯文字动态 328 | sendCQCode.append(uname) 329 | sendCQCode.append('发表了动态:\n') 330 | content = card['card'] 331 | contentJo = json.loads(content) 332 | trueContent = contentJo['item']['content'] 333 | trueContent = getLimitedMessage(trueContent) 334 | sendCQCode.append(trueContent) 335 | sendCQCode.append('\nhttps://t.bilibili.com/{dynamicId}'.format(dynamicId=dynamicId)) 336 | elif dynamicType == 64: # 文章 337 | sendCQCode.append(uname) 338 | sendCQCode.append('发布了文章:\n') 339 | content = card['card'] 340 | contentJo = json.loads(content) 341 | cvid = str(contentJo['id']) 342 | title = contentJo['title'] 343 | summary = contentJo['summary'] 344 | coverImage = contentJo['image_urls'][0] 345 | sendCQCode.append(title) 346 | sendCQCode.append(getImageCqCode(coverImage)) 347 | sendCQCode.append('\n') 348 | sendCQCode.append(summary) 349 | sendCQCode.append('……') 350 | sendCQCode.append('\nhttps://www.bilibili.com/read/cv{cvid}'.format(cvid=cvid)) 351 | elif dynamicType == 8: # 投稿视频 352 | sendCQCode.append(uname) 353 | sendCQCode.append('投稿了视频:\n') 354 | bvid = card['desc']['bvid'] 355 | content = card['card'] 356 | contentJo = json.loads(content) 357 | title = contentJo['title'] 358 | coverImage = contentJo['pic'] 359 | videoDesc = contentJo['desc'] 360 | sendCQCode.append(title) 361 | sendCQCode.append('\n') 362 | sendCQCode.append(getImageCqCode(coverImage)) 363 | sendCQCode.append('\n') 364 | videoDesc = getLimitedMessage(videoDesc) 365 | sendCQCode.append(videoDesc) 366 | sendCQCode.append('\n') 367 | sendCQCode.append('\nhttps://www.bilibili.com/video/{bvid}'.format(bvid=bvid)) 368 | elif dynamicType == 1: # 转发动态 369 | sendCQCode.append(uname) 370 | sendCQCode.append('转发了动态:\n') 371 | content = card['card'] 372 | contentJo = json.loads(content) 373 | currentContent = contentJo['item']['content'] 374 | sendCQCode.append(currentContent) 375 | sendCQCode.append('\n') 376 | originType = contentJo['item']['orig_type'] 377 | originContentJo = json.loads(contentJo['origin']) # 378 | if originType == 2: 379 | originUser = originContentJo['user']['name'] 380 | sendCQCode.append('>>') 381 | sendCQCode.append(originUser) 382 | sendCQCode.append(':') 383 | sendCQCode.append('\n') 384 | originTrueContent = originContentJo['item']['description'] 385 | originTrueContent = getLimitedMessage(originTrueContent) 386 | sendCQCode.append(originTrueContent) 387 | elif originType == 4: 388 | originUser = originContentJo['user']['name'] 389 | sendCQCode.append('>>') 390 | sendCQCode.append(originUser) 391 | sendCQCode.append(':') 392 | sendCQCode.append('\n') 393 | trueContent = originContentJo['item']['content'] 394 | trueContent = getLimitedMessage(trueContent) 395 | sendCQCode.append(trueContent) 396 | elif originType == 8: 397 | bvid = card['desc']['origin']['bvid'] 398 | title = originContentJo['title'] 399 | coverImage = originContentJo['pic'] 400 | ownerName = originContentJo['owner']['name'] 401 | sendCQCode.append('>>') 402 | sendCQCode.append(ownerName) 403 | sendCQCode.append('的视频:') 404 | sendCQCode.append(title) 405 | sendCQCode.append('\n') 406 | sendCQCode.append(getImageCqCode(coverImage)) 407 | sendCQCode.append('\n') 408 | sendCQCode.append('>>') 409 | sendCQCode.append(bvid) 410 | elif originType == 64: 411 | title = originContentJo['title'] 412 | cvid = str(originContentJo['id']) 413 | ownerName = originContentJo['author']['name'] 414 | sendCQCode.append('>>') 415 | sendCQCode.append(ownerName) 416 | sendCQCode.append('的文章:') 417 | sendCQCode.append(title) 418 | sendCQCode.append('\n') 419 | sendCQCode.append('>>cv') 420 | sendCQCode.append(cvid) 421 | else: 422 | sendCQCode.append('>>暂不支持的源动态类型,请进入动态查看') 423 | sendCQCode.append('\nhttps://t.bilibili.com/{dynamicId}'.format(dynamicId=dynamicId)) 424 | else: 425 | sendCQCode.append(uname) 426 | sendCQCode.append('发表了动态:\n') 427 | sendCQCode.append('暂不支持该动态类型,请进入原动态查看') 428 | sendCQCode.append('\nhttps://t.bilibili.com/{dynamicId}'.format(dynamicId=dynamicId)) 429 | sv.logger.info(f'type={dynamicType},暂不支持此类动态') 430 | msg = ''.join(sendCQCode) 431 | if push_uids[uid][0] == 'all': 432 | await broadcast(msg, sv_name='bili-dynamic') 433 | else: 434 | await broadcast(msg, push_uids[uid]) 435 | time.sleep(0.5) 436 | except Exception as e: 437 | sv.logger.info(f'B站动态检查发生错误 uid={uid}\n' + traceback.format_exc()) 438 | sv.logger.info('B站动态检查结束') 439 | # 直播状态检查 440 | sv.logger.info('B站直播状态检查开始') 441 | for uid in uids: 442 | try: 443 | header = { 444 | 'Referer': 'https://space.bilibili.com/{user_uid}/'.format(user_uid=uid), 445 | 'Cookie': bilibiliCookie 446 | } 447 | resp = await aiorequests.get('https://api.bilibili.com/x/space/acc/info?mid={user_id}'.format(user_id=uid), headers=header, timeout=20) 448 | res = await resp.json() 449 | if res['data']['live_room']['liveStatus'] == 1 and not room_states[uid]: 450 | room_states[uid] = True 451 | sendCQCode = [] 452 | userName = all_user_name[uid] 453 | sendCQCode.append(userName) 454 | sendCQCode.append('开播了:\n') 455 | sendCQCode.append(res['data']['live_room']['title']) 456 | sendCQCode.append('\n') 457 | sendCQCode.append(getImageCqCode(res['data']['live_room']['cover'])) 458 | sendCQCode.append('\n') 459 | sendCQCode.append(res['data']['live_room']['url']) 460 | msg = ''.join(sendCQCode) 461 | if push_uids[uid][0] == 'all': 462 | await broadcast(msg, sv_name='bili-dynamic') 463 | else: 464 | await broadcast(msg, push_uids[uid]) 465 | elif room_states[uid] and res['data']['live_room']['liveStatus'] == 0: 466 | room_states[uid] = False 467 | sendCQCode = [] 468 | userName = res['data']['name'] 469 | sendCQCode.append(userName) 470 | sendCQCode.append('下播了') 471 | msg = ''.join(sendCQCode) 472 | if push_uids[uid][0] == 'all': 473 | await broadcast(msg, sv_name='bili-dynamic') 474 | else: 475 | await broadcast(msg, push_uids[uid]) 476 | time.sleep(0.5) 477 | except Exception as e: 478 | sv.logger.info(f'B站直播检查发生错误 uid={uid}\n' + traceback.format_exc()) 479 | sv.logger.info('B站直播状态检查结束') 480 | isOnChecking = False 481 | 482 | 483 | async def make_big_image(image_urls, size, imageNum): 484 | dirPath = path.join(path.dirname(__file__), 'res', 'image') 485 | for url in image_urls: # 下载全部图片 486 | imageResp = await aiorequests.get(url) 487 | image = await imageResp.content 488 | imgFilename = url.rsplit('/', 1)[1] 489 | imagePath = path.join(dirPath, imgFilename) 490 | with open(path.abspath(imagePath), 'wb') as f: 491 | f.write(image) 492 | if imageNum == 9: 493 | newImg = Image.new('RGB', (size[0] * 3, size[1] * 3), 255) 494 | currentImageCount = 0 495 | for y in range(3): 496 | for x in range(3): 497 | img = Image.open(path.join(dirPath, image_urls[currentImageCount].rsplit('/', 1)[1])) 498 | newImg.paste(img, (x * size[0], y * size[1])) 499 | currentImageCount += 1 500 | savePath = image_urls[0].rsplit('/', 1)[1].split('.')[0] + 'make.jpg' 501 | newImg.save(savePath) 502 | return savePath 503 | if imageNum == 6: 504 | newImg = Image.new('RGB', (size[0] * 3, size[1] * 2), 255) 505 | currentImageCount = 0 506 | for y in range(2): 507 | for x in range(3): 508 | img = Image.open(path.join(dirPath, image_urls[currentImageCount].rsplit('/', 1)[1])) 509 | sv.logger.info(path.join(dirPath, image_urls[currentImageCount].rsplit('/', 1)[1])) 510 | sv.logger.info(currentImageCount) 511 | newImg.paste(img, (x * size[0], y * size[1])) 512 | currentImageCount += 1 513 | savePath = path.join(dirPath, image_urls[0].rsplit('/', 1)[1].split('.')[0] + '_make.jpg') 514 | newImg.save(savePath) 515 | return savePath 516 | pass 517 | 518 | 519 | @sv.on_fullmatch(('重新载入B站动态推送配置', '重新载入动态推送配置')) 520 | async def reload_config(bot, ev): 521 | if check_priv(ev, SUPERUSER): 522 | await loadConfig() 523 | await bot.send(ev, '成功重新载入配置') 524 | --------------------------------------------------------------------------------