def GetCTypeAndOwner(tinfo): ctype, owner = tinfo, tinfo if ctype in ('buddy', 'group', 'discuss'): return ctype, None elif isinstance(owner, QContact) and owner.ctype in ('group', 'discuss'): return owner.ctype + '-member', owner else: DEBUG(tinfo) assert False
def init_msg_queue(self, limit=10): weibo_top_cnt = 0 for weibo_id in self.weibo_ids: is_top = 0 res = self.get_member_weibo(weibo_id) res = filter(lambda x: x["card_type"] == 9, res.json()["cards"]) for i in res: id = i["mblog"]["id"] self.weibo_msg_queue[weibo_id].append(id) if "isTop" in i["mblog"].keys(): is_top = 1 self.weibo_top_id[weibo_id] = id weibo_top_cnt += is_top time.sleep(0.01) DEBUG("init weibo_id:%s success! has weibo:%s \nids:%s" \ %(weibo_id, len(res), ' '.join(self.weibo_msg_queue[weibo_id]))) DEBUG("Init weibo msg queue success.") DEBUG("%s/%s 有置顶微博." % (weibo_top_cnt, len(self.weibo_ids)))
def monitor_modian(bot): """ 监控微打赏 :return: """ global modian_handler DEBUG('监控摩点集资情况') for modian in global_config.MODIAN_ARRAY: r = modian_handler.query_project_orders(modian) modian_handler.parse_order_details(r, modian)
def get_memberLive_msg(self, limit=50, memberId=0, groupId=0): url = "https://plive.48.cn/livesystem/api/live/v1/memberLivePage" params = { "type": 0, "limit": limit, "giftUpdTime": 1503766100000, "memberId": memberId, "groupId": groupId, "lastTime": 0 } res = self.session.post(url, json=params, headers=self.memberLive_header_args()).json() if res["status"] == 200: DEBUG("Get member live success.") else: DEBUG("fail to get member live.") return res
def __init__(self, sock, addr, server): self.sock = sock self.addr = addr self.name = 'IRC-CLIENT<%s/%s>' % addr self.server = server self.bot = server.bot self.servername = self.server.name self.handler = self.waitNick self.sock.settimeout(5) StartDaemonThread(self.recvLoop) DEBUG('%s connected', self.name)
def monitor_wds(bot): """ 监控微打赏 :param bot: :return: """ global wds_handler DEBUG('监控微打赏') for wds in global_config.WDS_ARRAY: r = wds_handler.monitor_wds_comment(wds) wds_handler.parse_wds_comment2(r, wds)
def check_member_info(content): tokens = content.split('-') if len(tokens) != 2: return None idol_name = tokens[0] type_name = tokens[1] DEBUG('%s %s'%(idol_name, type_name)) if re.compile(u'^[\u4e00-\u9fa5]{2,4}$').match(idol_name.decode('utf-8')): if type_name in ["live", "love", "review", "wds", "weibo"]: return type_name return None
def send(self, prefix, command, params, tail): words = [':' + prefix, command.upper()] + params + [':' + tail] msg = ' '.join(words) try: self.sock.sendall(STR2BYTES(msg) + b'\r\n') except socket.timeout: ERROR('在向 %s 发送数据时出现 %s', self.name, 'SOCKET-TIMEOUT') except socket.error: ERROR('在向 %s 发送数据时出现 %s', self.name, 'SOCKET-ERROR') self.close() else: DEBUG('%s ==> %s: %r', self.servername, self.name, msg)
def monitor_member_weibo(bot): global weibo_monitor newWB = weibo_monitor.startMonitor() if newWB is not None: DEBUG(newWB) member_weibo_groups = QQHandler.list_group( global_config.MEMBER_WEIBO_GROUPS) message = '官博有新消息啦:\n %s\n发送时间: %s' % (newWB['scheme'], newWB['created_at']) if newWB['created_at'] == '刚刚': QQHandler.send_to_groups(member_weibo_groups, message)
def FetchNewBuddyInfo(self, uin): try: qq = self.fetchBuddyQQ(uin) nick = self.fetchBuddyDetailInfo(uin).get('nick', '') binfo = dict(uin=uin, qq=qq, nick=nick, name=nick) except RequestError: return None except: DEBUG('', exc_info=True) return None else: return binfo
def parseLines(self, lines): if self.handler is None: return for line in lines: line = line.rstrip(b'\r').lstrip() if not line: continue try: line = BYTES2STR(line) except Exception as e: DEBUG('%r\n%r', e, line) continue head, sep, tail = line.partition(' :') params = head.rstrip().split() command, params = params[0].upper(), params[1:] DEBUG('%s <== %s: %r', self.servername, self.name, line) DEBUG('%r, %r, %r', command, params, tail) self.handler(command, params, tail)
def Dump(self): d = self.__dict__.copy() session = d.pop('session') picklePath = d.pop('picklePath') d.pop('autoSession') try: with open(picklePath, 'wb') as f: pickle.dump((session.__dict__, d), f) except Exception as e: WARN('保存登录信息失败:%s %s', e, picklePath) else: DEBUG('登录信息及联系人资料已保存至文件:file://%s' % picklePath)
def init_msg_queues(self, room_ids): """ 初始化房间消息队列 避免每次一开启 就发送n多消息 :param room_ids: :return: """ if len(room_ids) > 0: try: self.member_room_msg_ids = [] self.member_room_comment_ids = [] self.member_live_ids = [] self.unread_msg_amount = 0 for room_id in room_ids: r1 = self.get_member_room_msg(room_id[1]) # r2 = self.get_member_room_comment(room_id) r1_json = json.loads(r1) # r2_json = json.loads(r2) for r in r1_json['content']['data']: msg_id = r['msgidClient'] self.member_room_msg_ids.append(msg_id) self.init_room_msg_ids_length = len(self.member_room_msg_ids) # for r in r2_json['content']['data']: # msg_id = r['msgidClient'] # self.member_room_comment_ids.append(msg_id) DEBUG('成员消息队列: %s', len(self.member_room_msg_ids)) # DEBUG('房间评论队列: %s', len(self.member_room_comment_ids)) DEBUG('房间未读消息数量: %d', self.unread_msg_amount) except Exception as e: ERROR('初始化房间消息队列失败') ERROR(e) else: return
def parse_watchMemberLive_msg(self, response, by_hand=False): all_live_ids = [] if "liveList" in response["content"].keys(): live_list = response["content"]["liveList"] for live_info in live_list: member_id = str(live_info["memberId"]) idol_name = live_info["title"] subtitle = live_info["subTitle"] streamPath = live_info["streamPath"] live_id = live_info["liveId"] live_url = 'https://h5.48.cn/2017appshare/memberLiveShare/index.html?id=%s' % live_id all_live_ids.append(member_id) if member_id in self.liveWatch_ids: if member_id not in self.member_live_msg_ids: DEBUG("%s开始直播!" % member_id) message = '你关注的小偶像正在直播!\n\n' message += ('%s : %s\n %s' % (idol_name, subtitle, live_url)) bot.SendTo( bot.List('group', self.group_id)[0], message) self.member_live_msg_ids.append(member_id) elif by_hand: message = '你关注的小偶像正在直播!\n\n' message += ('%s : %s\n %s' % (idol_name, subtitle, live_url)) bot.SendTo( bot.List('group', self.group_id)[0], message) else: DEBUG("%s在直播列表中!" % member_id) if not self.member_live_msg_ids: DEBUG("没有关注的小偶像在直播!") for member_id in self.member_live_msg_ids: if member_id not in all_live_ids: self.member_live_msg_ids.remove(member_id) DEBUG('%s关掉了直播' % member_id) return self.member_live_msg_ids
def update_wds_conf(bot): global wds_handler DEBUG('读取微打赏配置') ConfigReader.read_conf() wds_json = json.load(open("data/wds.json")) global_config.WDS_POSTSCRIPTS = wds_json['wds_postscripts'] # 微打赏集资PK链接数组初始化 global_config.WDS_NEED_DISPLAY_PK = wds_json['wds_need_display_pk'] for wds_pk_j in wds_json['wds_pk_activities']: wds = WDS(wds_pk_j['wds_pk_link'], wds_pk_j['wds_pk_title'], '', '', False) global_config.WDS_PK_ARRAY.append(wds) # 需要适应同时开多个链接的情况 global_config.WDS_ARRAY = [] for wds_j in wds_json['monitor_activities']: if wds_j['wds_need_display_rank'] is False: wds = WDS(wds_j['wds_link'], wds_j['wds_title'], wds_j['wds_moxi_id'], wds_j['wds_pro_id'], False) elif wds_j['wds_need_display_rank'] is True: wds = WDS(wds_j['wds_link'], wds_j['wds_title'], wds_j['wds_moxi_id'], wds_j['wds_pro_id'], True) global_config.WDS_ARRAY.append(wds) wds_handler.wds_array = global_config.WDS_ARRAY wds_handler.init_comment_queues() global_config.JIZI_NOTIFY_GROUPS = ConfigReader.get_property('qq_conf', 'jizi_notify_groups').split(';') wds_groups = QQHandler.list_group(global_config.JIZI_NOTIFY_GROUPS) wds_handler.wds_notify_groups = wds_groups DEBUG('JIZI_NOTIFY_GROUPS: %s, length: %d', ','.join(global_config.JIZI_NOTIFY_GROUPS), len(wds_handler.wds_notify_groups))
def QLogin(qq=None, user=None, conf=None): if not conf: conf = QConf(qq, user) conf.Display() if conf.qq: INFO('开始自动登录...') picklePath = conf.PicklePath() session = QSession() try: with open(picklePath, 'rb') as f: session.__dict__ = pickle.load(f) session.dbname = conf.absPath(session.dbbasename) except Exception as e: WARN('自动登录失败,原因:%s', e) else: INFO('成功从文件 "%s" 中恢复登录信息' % SYSTEMSTR2STR(picklePath)) try: session.TestLogin() except RequestError: WARN('自动登录失败,原因:上次保存的登录信息已过期') except Exception as e: WARN('自动登录失败,原因:%s', e) DEBUG('', exc_info=True) else: return session, QContactDB(session), conf if os.path.exists(session.dbname): try: os.remove(session.dbname) except OSError: pass except: WARN('', exc_info=True) INFO('开始手动登录...') session = QSession() session.Login(conf) picklePath = conf.PicklePath() try: with open(picklePath, 'wb') as f: pickle.dump((session.__dict__), f) except Exception as e: WARN('保存登录信息及联系人失败:%s %s', (e, SYSTEMSTR2STR(picklePath))) else: INFO('登录信息已保存至: %s' % SYSTEMSTR2STR(picklePath)) return session, QContactDB(session), conf
def parse_member_live(self, response, member_id): """ 对直播列表进行处理,找到正在直播的指定成员 :param member_id: :param response: :return: """ rsp_json = json.loads(response) # DEBUG('keys of parse member live: %s', rsp_json['content'].keys()) # 当前没有人在直播 if 'liveList' not in rsp_json['content'].keys(): # print 'no live' DEBUG('当前没有人在直播') return live_list = rsp_json['content']["liveList"] DEBUG('当前正在直播的人数: %d', len(live_list)) # print '当前正在直播的人数: %d' % len(live_list) msg = '' # DEBUG('直播ID列表: %s', ','.join(self.member_live_ids)) for live in live_list: live_id = live['liveId'] # DEBUG(live.keys()) # print '直播人: %s' % live['memberId'] # DEBUG('直播人(response): %s, 类型: %s', live['memberId'], type(live['memberId'])) # DEBUG('member_id(参数): %s, 类型: %s', member_id, type(member_id)) DEBUG('memberId %s is in live: %s, live_id: %s', live['memberId'], live['title'], live_id) DEBUG('stream path: %s', live['streamPath']) # DEBUG('member_live_ids list: %s', ','.join(self.member_live_ids)) # DEBUG('live_id is in member_live_ids: %s', str(live_id in self.member_live_ids)) if live['memberId'] == int( member_id) and live_id not in self.member_live_ids: DEBUG('[被监控成员正在直播]member_id: %s, live_id: %', member_id, live_id) start_time = util.convert_timestamp_to_timestr( live['startTime']) stream_path = live['streamPath'] # 流地址 sub_title = live['subTitle'] # 直播名称 live_type = live['liveType'] url = 'https://h5.48.cn/2017appshare/memberLiveShare/index.html?id=%s' % live_id if live_type == 1: # 露脸直播 msg += '你的小宝贝儿开露脸直播了: %s\n直播链接: %s\n开始时间: %s' % ( sub_title, url, start_time) elif live_type == 2: # 电台直播 msg += '你的小宝贝儿开电台直播了: %s\n直播链接: %s\n开始时间: %s' % ( sub_title, url, start_time) self.member_live_ids.append(live_id) # 录制直播 # name = '%s_%s' % (member_id, live['startTime']) # # self.download.setName(name) # self.live_urls.put(name) # self.live_urls.put(stream_path) DEBUG(msg) if msg and len(self.member_live_groups) > 0: QQHandler.send_to_groups(self.member_live_groups, msg)
def onStartupComplete(bot): # 启动完成时被调用 # bot : QQBot 对象,提供 List/SendTo/GroupXXX/Stop/Restart 等接口,详见文档第五节 DEBUG('%s.onStartupComplete', __name__) global pocket48_handler global wds_handler global weibo_handler # global ROOM_IDS # global LIVE_IDS # global WEIBO_IDS ROOM_IDS = get_info_by_list(ROOM_NAMES, key = "room_id") LIVE_IDS = get_info_by_list(LIVE_NAMES, key = "member_id") WEIBO_IDS = get_info_by_list(WEIBO_NAMES, key = "weibo_id") DEBUG("ROOM_IDS:%s"%(' '.join(ROOM_IDS))) DEBUG("LIVE_IDS:%s"%(' '.join(LIVE_IDS))) DEBUG("WEIBO_IDS:%s"%(' '.join(WEIBO_IDS))) bot.SendTo(bot.List('group', GROUP_ID)[0], "官帝的机器人已启动~~") message = '目前监控的口袋房间:%s\n目前监控的直播:%s\n目前监控的微博:%s' \ %(' '.join(ROOM_NAMES), ' '.join(LIVE_NAMES), ' '.join(WEIBO_NAMES)) bot.SendTo(bot.List('group', GROUP_ID)[0], message) pocket48_handler = Pocket48Handler(room_ids = ROOM_IDS, \ group_id = GROUP_ID, liveWatch_ids = LIVE_IDS) pocket48_handler.login(POCKET48_USERNAME, POCKET48_PASSWORD) pocket48_handler.init_msg_queue(limit = 40) wds_handler = WdsHandler(group_id = GROUP_ID) weibo_handler = WeiboHandler(group_id = GROUP_ID, weibo_ids = WEIBO_IDS) weibo_handler.login(WB_USERNAME, WB_PASSWORD) weibo_handler.init_msg_queue(limit = 10) update_conf(bot)
def parse_room_comment(self, response): """ 对房间评论进行处理 :param response: :return: """ rsp_json = json.loads(response) msgs = rsp_json['content']['data'] # DEBUG('parse room comment reponse: %s', response) message = '' for msg in msgs: extInfo = json.loads(msg['extInfo']) platform = extInfo['platform'] msg_id = msg['msgidClient'] message_object = extInfo['messageObject'] if msg_id in self.member_room_comment_ids: continue self.member_room_comment_ids.append(msg_id) if extInfo['contentType'] == 1: # 普通评论 DEBUG('房间评论') message = ('【房间评论】[%s]-%s: %s\n' % (msg['msgTimeStr'], extInfo['senderName'], extInfo['text'])) + message elif extInfo['contentType'] == 3: # 房间礼物 DEBUG('礼物') else: DEBUG('其他类型评论') INFO('message: %s', message) DEBUG('length of comment groups: %d', len(self.member_room_comment_msg_groups)) if message and len(self.member_room_comment_msg_groups) > 0: QQHandler.send_to_groups(self.member_room_comment_msg_groups, message) DEBUG('房间评论队列: %s', len(self.member_room_comment_ids))
def StrOfList(self, ctype, info1=None, info2=None): if ctype in ('buddy', 'group', 'discuss'): return self.strOfList(ctype, cinfo=info1) elif ctype in ('group-member', 'discuss-member'): assert info1 oinfo, cinfo = info1, info2 result = [] for owner in self.List(ctype[:-7], oinfo): result.append(self.strOfList(owner, cinfo)) if not result: return '%s(%s)不存在' % (CTYPES[ctype[:-7]], oinfo) else: return '\n\n'.join(result) else: DEBUG(ctype) assert False
def parse_bilibili_video_list(self, bilibili_video_list): msg = '' for bilibili_video in bilibili_video_list: video_id = bilibili_video['aid'] if video_id not in self.bilibili_video_ids: timeStamp = bilibili_video['created'] localTime = time.localtime(timeStamp) strTime = time.strftime("%Y-%m-%d %H:%M:%S", localTime) address = 'https://www.bilibili.com/video/av%s' % (video_id) msg += '%s\n投稿时间:%s\n传送门:%s\n' % (bilibili_video['title'], strTime, address) self.bilibili_video_ids.append(video_id) DEBUG(msg) if msg and len(self.member_room_msg_groups) > 0: msg = 'b站官方账号更新:\n' + msg QQHandler.send_to_groups(self.member_room_msg_groups, msg)
def StrOfList(self, ctype, info1=None, info2=None): if ctype in ('buddy', 'group', 'discuss'): return self.strOfList(ctype, cinfo=info1) elif ctype in ('group-member', 'discuss-member'): assert info1 oinfo, cinfo = info1, info2 cl = self.List(ctype[:-7], oinfo) if cl is None: return '错误:无法向 QQ 服务器获取联系人资料' elif not cl: return '错误:%s(%s)不存在' % (CTYPES[ctype[:-7]], oinfo) else: return '\n\n'.join(self.strOfList(owner,cinfo) for owner in cl) else: DEBUG(ctype) assert False
def init_bilibili_video_queues(self, bilibili_video_list): """ 初始化b站投稿队列 避免每次一开启 就发送n多消息 :param room_ids: :return: """ try: self.bilibili_video_ids = [] for bilibili_video in bilibili_video_list: video_id = bilibili_video['aid'] self.bilibili_video_ids.append(video_id) DEBUG('b站视频消息队列: %s', len(self.bilibili_video_ids)) except Exception as e: ERROR('初始化b站视频消息队列失败') ERROR(e)
def login(self, username, password): if self.is_login: return login_url = "https://puser.48.cn/usersystem/api/user/v1/login/phone" params = { "account": username, "password": password, } res = self.session.post(login_url, json=params, headers=self.login_header_args()).json() if res["status"] == 200: self.token = res["content"]["token"] self.is_login = True DEBUG("Pocket48 login success, token is %s" % self.token) else: ERROR("login false")
def Poll(self): try: result = self.smartRequest( url = 'https://d1.web2.qq.com/channel/poll2', data = { 'r': JsonDumps({ 'ptwebqq':self.ptwebqq, 'clientid':self.clientid, 'psessionid':self.psessionid, 'key':'' }) }, Referer = ('http://d1.web2.qq.com/proxy.html?v=20151105001&' 'callback=1&id=2'), expectedCodes = (0, 100003, 100100, 100012) ) # "{'retcode': 0, 'retmsg': 'ok', 'errmsg': 'error'}" # if type(result) is dict and \ # result.get('retcode', 1) == 0 and \ # result.get('errmsg', '') == 'error': # DEBUG(result) # raise RequestError except RequestError: ERROR('接收消息出错,开始测试登录 cookie 是否过期...') try: self.TestLogin() except RequestError: ERROR('登录 cookie 很可能已过期') raise else: INFO('登录 cookie 尚未过期') return 'timeout', '', '', '' else: if (not result) or (not isinstance(result, list)): DEBUG(result) return 'timeout', '', '', '' else: result = result[0] ctype = { 'message': 'buddy', 'group_message': 'group', 'discu_message': 'discuss' }[result['poll_type']] fromUin = str(result['value']['from_uin']) memberUin = str(result['value'].get('send_uin', '')) content = FaceReverseParse(result['value']['content']) return ctype, fromUin, memberUin, content
def parse_memberReviewLive_msg(self, response, limit=5): message = "" if "reviewList" in response["content"].keys(): DEBUG("获得录播列表") live_list = response["content"]["reviewList"] live_list = live_list[:limit] message += "小偶像的录播:\n\n" for live_info in live_list: idol_name = live_info["title"] subtitle = live_info["subTitle"] streamPath = live_info["streamPath"] startTime = convert_timestamp_to_timestr( live_info["startTime"]) live_id = live_info["liveId"] member_id = live_info["memberId"] message += ('%s : %s [%s]\n %s\n\n' % (idol_name, subtitle, startTime, streamPath)) bot.SendTo(bot.List('group', self.group_id)[0], message)
def QLogin(qq=None, user=None): conf = QConf(qq, user) conf.Display() if conf.qq: INFO('开始自动登录...') picklePath = conf.PicklePath() session = QSession() try: with open(picklePath, 'rb') as f: session.__dict__ = pickle.load(f) except Exception as e: WARN('自动登录失败,原因:%s', e) else: INFO('成功从文件 "%s" 中恢复登录信息' % picklePath) try: session.TestLogin() except RequestError: WARN('自动登录失败,原因:上次保存的登录信息已过期') except Exception as e: WARN('自动登录失败,原因:%s', e) DEBUG('', exc_info=True) else: return session, QContactDB(session), conf try: os.remove(session.dbname) except: pass INFO('开始手动登录...') session = QSession() session.Login(conf) picklePath = conf.PicklePath() try: with open(picklePath, 'wb') as f: pickle.dump((session.__dict__), f) except Exception as e: WARN('保存登录信息及联系人失败:%s %s', (e, picklePath)) else: INFO('登录信息已保存至文件:file://%s' % picklePath) return session, QContactDB(session), conf
def parse_memberLive_msg(self, response): message = "" if "liveList" in response["content"].keys(): DEBUG("获得直播列表") live_list = response["content"]["liveList"] message = message + "当前共有%s人在直播:\n\n" % (len(live_list)) for live_info in live_list: idol_name = live_info["title"] subtitle = live_info["subTitle"] streamPath = live_info["streamPath"] live_id = live_info["liveId"] member_id = live_info["memberId"] live_url = 'https://h5.48.cn/2017appshare/memberLiveShare/index.html?id=%s' % live_id message += ('%s : %s\n %s\n\n' % (idol_name, subtitle, live_url)) bot.SendTo(bot.List('group', self.group_id)[0], message) else: bot.SendTo(bot.List('group', self.group_id)[0], "当前没有小偶像在直播~~")
def FetchTable(self, tinfo): ctype, owner = GetCTypeAndOwner(tinfo) try: if ctype == 'buddy': table = self.fetchBuddyTable() elif ctype == 'group': table = self.fetchGroupTable() elif ctype == 'discuss': table = self.fetchDiscussTable() elif ctype == 'group-member': table = self.fetchGroupMemberTable(owner) else: # 'discuss-member': table = self.fetchDiscussMemberTable(owner) except RequestError: return None except: DEBUG('', exc_info=True) return None else: return table
def update_modian_conf(bot): global modian_handler INFO('读取摩点配置') ConfigReader.read_conf() modian_json = json.load(open("data/modian.json")) global_config.MODIAN_POSTSCRIPTS = modian_json['modian_postscripts'] # 摩点集资PK链接数组初始化 global_config.MODIAN_NEED_DISPLAY_PK = modian_json[ 'modian_need_display_pk'] for modian_pk_j in modian_json['modian_pk_activities']: global_config.MODIAN_PK_ARRAY.append(modian_pk_j) # 需要适应同时开多个链接的情况 global_config.MODIAN_ARRAY = [] for modian_j in modian_json['monitor_activities']: if modian_j['modian_need_display_rank'] is False: modian = ModianEntity(modian_j['modian_link'], modian_j['modian_title'], modian_j['modian_pro_id'], False) elif modian_j['wds_need_display_rank'] is True: modian = ModianEntity(modian_j['modian_link'], modian_j['modian_title'], modian_j['modian_pro_id'], True) global_config.MODIAN_ARRAY.append(modian) modian_handler.modian_project_array = global_config.MODIAN_ARRAY modian_handler.init_order_queues() global_config.JIZI_NOTIFY_GROUPS = ConfigReader.get_property( 'qq_conf', 'jizi_notify_groups').split(';') modian_groups = global_config.JIZI_NOTIFY_GROUPS modian_handler.modian_notify_groups = modian_groups DEBUG('JIZI_NOTIFY_GROUPS: %s, length: %d', ','.join(global_config.JIZI_NOTIFY_GROUPS), len(modian_handler.modian_notify_groups))