def run(): INFO('读入配置文件...') try: file = open(Configpath + '\config.json', mode='r', encoding='utf-8') config = json.load(file) file.close() except: ERROR( '读入配置文件或解析时发生异常,检查配置文件是否正确,默认路径为.douyin目录下的config.json。如果没有则需要复制文件 _config(将我复制改名为config.json).json 为 config.json' ) return INFO('开始初始化所有需要监听的抖音用户') user = [] user.clear() delay = int(config['delay']) for u in config['config']: if u.get('sec_uid'): user.append(dy(u)) else: ERROR(f'{u}未填写sec_uid') if len(user) == 0: INFO('没有载入任何需要监听的用户') return INFO('开始轮询抖音') i = 0 while True: for u in user: #print(u.vid) if u.check(): for g in u.conf['Group']: Send['sendGroupMsg'](g, u.msg) Send['sendGroupMsg'](g, u.video) time.sleep(delay) time.sleep(5)
def run_task(): # 读入配置文件 INFO('读入配置文件...') try: file = open(Configpath + '\config.json', mode='r', encoding='utf-8') config = json.load(file) file.close() except: ERROR( '读入配置文件或解析时发生异常,检查配置文件是否正确,默认路径为.LIVEBILI目录下的config.json。如果没有则需要复制文件 _config(将我复制改名为config.json).json 为 config.json 如果你已经配置好了BILI的配置文件也可将其直接复制过来使用(必须要填写roomid)' ) return INFO('开始初始化所有需要监听的用户') user = [] user.clear() for u in config['config']: if u.get('roomid'): user.append(Livebiliws(u)) else: ERROR(f'{u}未填写roomid') if len(user) == 0: INFO('没有载入任何需要监听的用户') return INFO('开始启动ws') i = 0 for u in user: Thread(target=u.run_forever, name=f'[T{i}] {u.roomid}-websocket').start() i += 1 #开始刷新用户信息,间隔5秒 for u in user: u.RefreshInfo() time.sleep(5)
def Import_module(modeule: list): '''安装列表内的模块''' # 导入模块 # 包名为目录名,模块为文件夹下的__init__.py,启动后会调用执行一次__init__下的Main函数, # 如果不存Main函数将不会执行此模块任何方法 for t in modeule: m = __import__(name=t) if 'Main' in dir(m): INFO('安装模块:' + str(m)) tasks.append(m) else: ERROR('模块:' + str(m) + '未找到Main') ERROR(dir(m))
def __init__(self, conf: dict): self.conf = conf self.sec_uid = conf['sec_uid'] self.name = conf['showname'] if not self.GetInfo(): '''secuid验证失败''' ERROR(f'{conf}:的sec_uid无效') self.vid = [].copy()
def run_forever(self): '''阻塞运行连接ws,并接受消息''' try: #检查sessionstr是否可用 j = self.GET('config','sessionKey='+self.sessionstr) if j.get('sessionKey') == self.sessionstr: pass elif j.get('code') == 3: #sessionstr失效 INFO(f'{j["msg"]},重新获取') self.__Getsessionstr__() else: ERROR(j['msg']) return True return self.ws.run_forever(ping_interval=30,ping_timeout=3) except: ERROR(f'mirai_api_http在ws连接时发生异常。') return True
def getconfig(): try: file = open(Configpath1, mode='r', encoding='utf-8') config = json.load(file) file.close() return json.dumps({'code':200,'msg':'','data':config},ensure_ascii=False) except: text='读取配置文件或解析时发生异常,检查配置文件是否正确,默认路径为.BILI目录下的config.json。如果没有则需要复制文件 _config(将我复制改名为config.json).json 为 config.json' ERROR('HTTPAPI-'+text) return json.dumps({'code':500,'msg':'','data':text},ensure_ascii=False)
def run(): #读取配置文件 try: file = open(path, mode='r', encoding='utf-8') #转化yml配置数据 data = yaml.load(file, Loader=yaml.FullLoader) file.close() #print(data) except Exception as e: ERROR(f'读入配置文件时发生异常,无法继续运行Acfun模块。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') return #实例化所有需要监听的对象放进列表里 user = [] for u in data['user']: INFO('初始化用户:'+u['uid']) us = Acfun(u) user.append(us) #开始循环执行 while True: i = 0 l = len(user) while i < l: try:#获取信息 user[i].Getinfo() user[i].GetDynamic() #判断 if user[i].IsNewLive():#开播 INFO(f'主播{user[i].Name}开播了~') SendGroupsMsg(user[i].user['group'],user[i].LiveLoad()) if user[i].IsNewVideo():#有新视频 INFO(f'主播{user[i].Name}有新视频了~') SendGroupsMsg(user[i].user['group'],user[i].VideoLoad()) if user[i].IsNewDynamic():#有新动态 INFO(f'主播{user[i].Name}有新动态了~') SendGroupsMsg(user[i].user['group'],user[i].DynamincLoad()) pass except Exception as e: ERROR(f'处理时发现异常,跳过!。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') pass i = i + 1 time.sleep(data.get('delay',5)) time.sleep(2)
def GET(self,path,data): url = f'{self.host}{path}' try: r = requests.get(url, params=data) if r.status_code == 200: return r.json() else: return {'retcode':r.status_code,'msg':f'code:{r.status_code},code=401表示access_token错误'} except Exception as e: ERROR(f'cq在http_get时发生错误:url:{url} data:{str(data)};异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') return {'retcode':-1,'msg':'request.get 发生异常'}
def on_GroupMessage(Message: MsgChain, sender: GroupInfo): if Message.GetCQ().startswith('我想吃'): try: INFO('出现食谱查询指令:'+Message.GetCQ()) name = Message.GetCQ()[3:] if name.isnumeric(): Send['sendGroupMsg'](sender.GroupId,MsgChain().joinPlain(Getfangfa(name))) else: Send['sendGroupMsg'](sender.GroupId,MsgChain().joinImg(Path=合成图片(Getname(name)))) except: ERROR('食谱查询异常')
def savegift(self, TIME, UNAME, UID, GIFTNAME, GIFTNUM, PRICE, GIFTCOIN): '''保存礼物日志''' t = f"INSERT INTO GIFT VALUES ('{TIME}', '{UNAME}', {UID}, '{GIFTNAME}', {GIFTNUM}, {PRICE}, '{GIFTCOIN}' )" #print(t) try: self.sql.execute(t) self.sql3.commit() except Exception as e: ERROR( f'保存礼物日志发生异常:异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' )
def Getsearch(self, uid, ps=10): '''通过UID获取作品列表默认为前10个''' url = f'https://api.bilibili.com/x/space/arc/search?mid={str(uid)}&pn=1&ps={str(ps)}' try: r = requests.get(url=url, headers=self.h) except Exception as e: ERROR( f'Request访问时发生异常:。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' ) r = Response() return r
def Get_RoomS_info(self, roomids: list): '''批量获得所有直播间info,包括开播状态''' url = 'https://api.live.bilibili.com/room/v2/Room/get_by_ids' data = {'ids': roomids} try: r = requests.post(url=url, data=json.dumps(data), headers=self.h) except Exception as e: ERROR( f'Request访问时发生异常:。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' ) r = None return r
def Getaweme(self): '''获取作品列表''' url = 'https://www.iesdouyin.com/web/api/v2/aweme/post/?count=10&sec_uid=' + self.sec_uid try: r = requests.get(url) if r.status_code == 200: j = r.json() return j['aweme_list'] return [] except: ERROR(f'获取用户视频列表时发生异常') return []
def Get_Info(self, roomid): '''通过ROOMID获取直播间信息,支持短号''' url = 'https://api.live.bilibili.com/room/v1/Room/get_info?room_id=' + \ str(roomid) try: r = requests.get(url=url, headers=self.h) except Exception as e: ERROR( f'Request访问时发生异常:。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' ) r = Response() return r
def Get_Master_info(self, uid): '''通过UID获得昵称、UP等级、roomid、开通的勋章名、直播间公告、性别''' url = 'https://api.live.bilibili.com/live_user/v1/Master/info?uid=' + \ str(uid) try: r = requests.get(url=url, headers=self.h) except Exception as e: ERROR( f'Request访问时发生异常:。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' ) r = Response() return r
def Get_space_history(self, uid): '''通过UID获得10条此用户的动态信息''' url = 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?&host_uid=' + \ str(uid) try: r = requests.get(url=url, headers=self.h) except Exception as e: ERROR( f'Request访问时发生异常:。异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' ) r = Response() return r
def savedanmu(self, TIME, UNAME, UID, MSG): '''保存弹幕''' t = f"INSERT INTO DANMU VALUES ('{TIME}', '{UNAME}', {UID}, '{MSG}' )" #print(t) try: self.sql.execute(t) self.sql3.commit() except Exception as e: ERROR( f'保存弹幕信息发生异常:异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' )
def __Getsessionstr__(self): '''获取sessionstr''' data = {'authKey': self.authkey} r = self.POST('auth', json.dumps(data)) if r['code'] == 0: self.sessionstr = r['session'] INFO(f'session:{self.sessionstr}') else: #err = '错误的MIRAI API HTTP auth key' ERROR(r['msg']) return False '''获取到session,绑定机器人''' data = {'sessionKey': self.sessionstr, 'qq': int(self.BOTQQ)} r = self.POST('verify', json.dumps(data)) if r['code'] == 0: INFO("绑定机器人成功") super().__init__(self.host.replace('http','ws')+'all?sessionKey='+self.sessionstr) else: err = r['msg'] ERROR(err) return False return True
def LiveLoad(self) -> MsgChain: '''开播推送信息''' if self.Live == False: #为开播,不发送 ERROR("主播未开播,无法载入相关信息") return MsgChain() Msg = MsgChain() if self.user.get('ATall'): Msg.joinAT(-1) Msg.joinPlain(" \n") Msg.joinPlain( f'你的小可爱[{self.Name}]开播啦~\n{self.LiveInfo.get("title","")}\n{self.LiveInfo.get("type",{}).get("name","")}\nhttps://live.acfun.cn/live/{self.Uid}' ) Msg.joinImg(Url=self.LiveInfo.get('coverUrls', [""])[0]) return Msg
def GetInfo(self): try: r = requests.get( 'https://www.iesdouyin.com/web/api/v2/user/info/?sec_uid=' + self.sec_uid) if r.status_code == 200: j = r.json() if j['status_code'] == 0: self.name = j['user_info']['nickname'] return True return False except: ERROR(f'获取用户信息时发生异常') return False
def GetDynamic(self): '''获取动态列表默认前10条详细信息的json列表和dynamicid列表,网络错误,或者无作品返回None''' try: j = self.api.Get_space_history(self.uid).json() except Exception as e: ERROR(f'获取动态信息时发生异常,此处异常应检查网络!异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') j = None Dynamicid = [] if j and j.get('code') == 0: cards = j.get('data', {}).get('cards', []) for d in cards: Dynamicid.append(d['desc']['dynamic_id']) return cards, Dynamicid else: return [], []
def GetVideo(self, ps=10): '''获取视频列表默认前10条详细信息的json列表和aid列表,网络错误,或者无作品返回None''' try: j = self.api.Getsearch(uid=self.uid, ps=ps).json() except Exception as e: ERROR(f'获取动态信息时发生异常,此处异常应先检查网络!异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') j = None videoaid = [] if j and j.get('code') == 0: vlist = j.get('data', {}).get('list', {}).get('vlist', []) for v in vlist: videoaid.append(v['aid']) return vlist, videoaid else: return [], []
def GET(self, path, data): '''为内部访问使用方法''' if data == '': d = '' else: d = '?' + data url = f"{self.host}{path}{d}" header = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) \ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 \ Safari/537.36'} try: return requests.get(url, headers=header).json() except Exception as e: ERROR(f'mirai在http_get时发生错误:url:{url} data:{str(data)};异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') return {'code':-1,'msg':'request.get 发生异常,请检查网络!'}
def Main(sendGroupMsg, SendFriendMsg): Send['sendGroupMsg'] = sendGroupMsg Send['SendFriendMsg'] = SendFriendMsg INFO('微博启动') # 打开json文件 try: fb = open( os.path.dirname(os.path.realpath(__file__)) + '\ini.json', 'rb') data = json.load(fb) fb.close() except: ERROR( '读入配置文件或解析时发生异常,检查配置文件是否正确,默认路径为.BILI目录下的ini.json。如果没有则需要复制文件 _ini(将我复制改名为ini.json).json 为 ini.json' ) return while True: chaWeribo(data) time.sleep(20)
def POST(self, path, data): '''为内部访问使用方法''' url = f"{self.host}{path}" header = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) \ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 \ Safari/537.36', 'content-type': 'application/json'} try: if type(data) == dict: data = json.dumps(data) print(data) r = requests.post(url, data, headers=header) print(r.text) return r.json() except Exception as e: ERROR(f'mirai在http_post时发生错误:url:{url} data:{str(data)};异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') return {'code':-1,'msg':'request.post 发生异常,请检查网络!'}
def DynamincLoad(self) -> MsgChain: '''载入将要推送的动态信息为MsgChain消息格式''' Msg = MsgChain() #判断一下是否有数据 if self.OldDynamic.get('resourceId') == None: ERROR("获取到的数据有问题,无法正常推送。") return Msg Type = self.OldDynamic.get('moment', {}).get('originResourceType') if self.user.get('ATall'): Msg.joinAT(-1) Msg.joinPlain(" \n") if not Type: Msg.joinPlain(f'你的小可爱{self.Name}发布一条新动态了哦,快来看看吧~\n') else: Msg.joinPlain(f'你的小可爱{self.Name}转发一条新动态了\n') Msg = Msg + self.DynamicOriginalLoad(self.OldDynamic) Msg.joinPlain('\n' + self.OldDynamic['shareUrl']) return Msg
def IsLive(self) -> bool: '''此方法判断返回是否开播,而不是当前直播状态''' if self.RoomStatus: try: j = self.api.Get_Info(self.roomid).json() except Exception as e: ERROR(f'获取直播间信息时发生异常,此处异常应先检查网络!异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') j = None if j and j.get('code') == 0: data = j.get('data', {}) live_status = bool(data.get('live_status', False)) if live_status != self.oldLiveStatus: self.oldLiveStatus = live_status self.roominfo.status = live_status if live_status: # 更新直播间info self.roominfo.area = data['parent_area_name'] + \ '·'+data['area_name'] self.roominfo.pic = data['user_cover'] self.roominfo.title = data['title'] self.roominfo.show_room_id = data['short_id'] return live_status else: self.oldLiveStatus = live_status self.roominfo.status = live_status return False '''废弃逻辑 if bool(data.get('live_status',False)) == self.oldLiveStatus: #表明记录的状态并没有改变,不做开播判断 return False elif data.get('live_status',False): #表明直播间状态live_status=1,开播,且本地记录状态为False self.oldLiveStatus=True self.roominfo.status=True return True else: self.roominfo.status=False self.oldLiveStatus=False return False ''' else: return False else: return False
def RefreshInfo(self): '''刷新用户部分信息''' try: j = requests.get( url= 'https://api.live.bilibili.com/room/v1/Room/get_info?room_id=' + str(self.roomid)).json() if j: self.uid = j['data']['uid'] self.title = j['data']['title'] self.area = j['data']['area_name'] j = requests.get( url= 'https://api.live.bilibili.com/live_user/v1/Master/info?uid=' + str(self.uid)).json() if j: self.info['name'] = j['data']['info']['uname'] except Exception as e: ERROR( f'刷新用户信息时发生异常:异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}' )
def Send(self,target:int,Msg: MsgChain,m = 'sendGroupMessage'): '''发送一条消息(可以为指定发送群消息还是私聊消息),消息为消息链类型,封装的类型''' try: #语音文件单独处理,后期可能会修改 if len(Msg.msg) == 1 and Msg.msg[0]['type'] == 'Voice': #因为语音只能单独发送 if Msg.msg[0]['url'] and not Msg.msg[0]['voiceId']: #进行上传并赋值 fname=f'./data/{str(time.time()*1000)}.mp3' with open( fname,'wb' ) as f: f.write(requests.get(Msg.msg[0]['url']).content) Msg.msg[0]['voiceId'] = self.uploadVoice(fname)['voiceId'] except: pass INFO(f'发送{"群" if m == "sendGroupMessage" else "私聊"}消息[{str(target)}] <- {Msg.GetCQ()}') s = {'sessionKey': self.sessionstr, 'target': target,'quote':Msg.Quote, 'messageChain': Msg.msg} ss = json.dumps(s) j = self.POST(m, ss) INFO(str(j)) if j.get('code') == 6: #指定文件不存在,出现于发送本地图片 #表示我发送的图片路径对于机器人而言并找不到,直接读取发送文件 try: mesg = MsgChain() for msg in Msg.msg: if msg['type'] == 'Image': p = msg['path'] img = self.uploadImage(p,'group' if m == 'sendGroupMessage' else 'friend') if img: mesg.joinImg(ImageId=img['imageId'], #Url=img['url'] ) else: #来点魔法,但这样使用会导致下一步发送消息时日志输出缺失 mesg.msg.append(msg.copy()) return self.Send(target,mesg,m) except Exception as e: ERROR(f'mirai在上传图片时发生错误:异常信息:{e.__doc__} 文件:{e.__traceback__.tb_frame.f_globals["__file__"]} 行号:{str(e.__traceback__.tb_lineno)}') else: return j
def on_GroupMessage(Message: MsgChain, sender: GroupInfo): if Message.GetCQ().startswith('./'): try: s = Message.GetCQ().split('/') if s[0] == '.' and len(s) >= 2 and is_number(s[1]): line = int(s[1]) try: m = s[2] except: m = 0 ll = bus.GETLinePIC(str(line), int(m)) l = None if len(ll) > 1: l = bus.pastepic(ll, int(m)) elif len(ll) == 1: l = ll[0] if l: Send['sendGroupMsg'](sender.GroupId, MsgChain().joinImg(Path=l)) else: Send['sendGroupMsg'](sender.GroupId, MsgChain().joinPlain('查询失败!')) except: ERROR('公交查询异常!')