def on_usernotice(self, chatconn, event): tags = { tag["key"]: tag["value"] if tag["value"] is not None else "" for tag in event.tags } if event.target != self.channel: return id = tags["user-id"] login = tags["login"] name = tags["display-name"] with DBManager.create_session_scope( expire_on_commit=False) as db_session: source = User.from_basics(db_session, UserBasics(id, login, name)) if event.arguments and len(event.arguments) > 0: msg = event.arguments[0] else: msg = None # e.g. user didn't type an extra message to share with the streamer with new_message_processing_scope(self): HandlerManager.trigger("on_usernotice", source=source, message=msg, tags=tags) if msg is not None: self.parse_message(msg, source, event, tags)
def bulk_get_user_basics_by_login(self, logins): bulk_user_data = self.bulk_get_user_data_by_login(logins) return [ UserBasics(user_data["id"], user_data["login"], user_data["display_name"]) if user_data is not None else None for user_data in bulk_user_data ]
def fetch_user_basics_from_authorization(self, authorization) -> UserBasics: """Fetch the UserBasics for the user identified by the given authorization object. `authorization` can be a UserAccessTokenManager or a tuple (ClientCredentials, UserAccessToken).""" user_data = self._fetch_user_data_from_authorization(authorization) return UserBasics(user_data["id"], user_data["login"], user_data["display_name"])
def bulk_get_user_basics_by_id( self, user_ids: List[str]) -> List[Optional[UserBasics]]: bulk_user_data = self.bulk_get_user_data_by_id(user_ids) return [ UserBasics(user_data["id"], user_data["login"], user_data["display_name"]) if user_data is not None else None for user_data in bulk_user_data ]
def on_pubmsg(self, chatconn, event): tags = { tag["key"]: tag["value"] if tag["value"] is not None else "" for tag in event.tags } id = tags["user-id"] login = event.source.user name = tags["display-name"] if event.source.user == self.nickname: return False if self.streamer == "forsen": if "zonothene" in login: self._ban(login) return True raw_m = event.arguments[0].lower() if raw_m.startswith("!lastseen forsen"): if len(raw_m) > len("!lastseen forsen2"): if raw_m[16] == " ": return True else: return True if raw_m.startswith("!lastseen @forsen"): if len(raw_m) > len("!lastseen @forsen2"): if raw_m[17] == " ": return True else: return True if self.streamer == "nymn": if "hades_k" in login: self.timeout_login(login, 3600, reason="Bad username") return True if "hades_b" in login: self.timeout_login(login, 3600, reason="Bad username") return True with DBManager.create_session_scope( expire_on_commit=False) as db_session: source = User.from_basics(db_session, UserBasics(id, login, name)) with new_message_processing_scope(self): res = HandlerManager.trigger("on_pubmsg", source=source, message=event.arguments[0], tags=tags) if res is False: return False self.parse_message(event.arguments[0], source, event, tags=tags)
def on_whisper(self, chatconn, event): tags = {tag["key"]: tag["value"] if tag["value"] is not None else "" for tag in event.tags} id = tags["user-id"] login = event.source.user name = tags["display-name"] with DBManager.create_session_scope(expire_on_commit=False) as db_session: source = User.from_basics(db_session, UserBasics(id, login, name)) self.parse_message(event.arguments[0], source, event, tags, whisper=True)
def on_message(self, message): msg = json.loads(message) if msg["type"].lower() == "pong": self.sent_ping = False return elif msg["type"].lower() == "reconnect": self.reset() return elif msg["type"].lower() == "message": if msg["data"][ "topic"] == "channel-bits-events-v2." + self.bot.streamer_user_id: messageR = json.loads(msg["data"]["message"]) user_id_of_cheer = str(messageR["data"]["user_id"]) bits_cheered = str(messageR["data"]["bits_used"]) with DBManager.create_session_scope() as db_session: user = User.find_by_id(db_session, user_id_of_cheer) if user is not None: HandlerManager.trigger("on_cheer", True, user=user, bits_cheered=bits_cheered) return try: message_message = json.loads(msg["data"]["message"]) if message_message["type"] == "reward-redeemed": userDict = message_message["data"]["redemption"]["user"] HandlerManager.trigger( "on_redeem", redeemer=UserBasics(userDict["id"], userDict["login"], userDict["display_name"]), redeemed_id=message_message["data"]["redemption"] ["reward"]["id"], user_input=message_message["data"]["redemption"].get( "user_input", ""), ) except Exception as e: log.error(e) elif msg["type"].lower() == "response": if not msg["error"]: return log.warning(msg)
def on_pubmsg(self, chatconn, event): tags = { tag["key"]: tag["value"] if tag["value"] is not None else "" for tag in event.tags } id = tags["user-id"] login = event.source.user name = tags["display-name"] if event.source.user == self.nickname: return False with DBManager.create_session_scope( expire_on_commit=False) as db_session: source = User.from_basics(db_session, UserBasics(id, login, name)) res = HandlerManager.trigger("on_pubmsg", source=source, message=event.arguments[0]) if res is False: return False self.parse_message(event.arguments[0], source, event, tags=tags)
def get_user_basics_by_login(self, login): user_data = self._get_user_data_by_login(login) if user_data is None: return None return UserBasics(user_data["id"], user_data["login"], user_data["display_name"])
def on_usernotice(self, source, tags, **rest): if "msg-id" not in tags: return if tags["msg-id"] == "resub": num_months = -1 substreak_count = 0 if "msg-param-months" in tags: num_months = int(tags["msg-param-months"]) if "msg-param-cumulative-months" in tags: num_months = int(tags["msg-param-cumulative-months"]) if "msg-param-streak-months" in tags: substreak_count = int(tags["msg-param-streak-months"]) if "msg-param-should-share-streak" in tags: should_share = bool(tags["msg-param-should-share-streak"]) if not should_share: substreak_count = 0 if "msg-param-sub-plan" not in tags: log.debug( f"subalert msg-id is resub, but missing msg-param-sub-plan: {tags}" ) return # log.debug('msg-id resub tags: {}'.format(tags)) # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead self.on_resub(source, num_months, tags["msg-param-sub-plan"], None, substreak_count) HandlerManager.trigger("on_user_resub", user=source, num_months=num_months) elif tags["msg-id"] == "subgift": num_months = 0 substreak_count = 0 if "msg-param-months" in tags: num_months = int(tags["msg-param-months"]) if "msg-param-cumulative-months" in tags: num_months = int(tags["msg-param-cumulative-months"]) if "msg-param-streak-months" in tags: substreak_count = int(tags["msg-param-streak-months"]) if "msg-param-should-share-streak" in tags: should_share = bool(tags["msg-param-should-share-streak"]) if not should_share: substreak_count = 0 if "display-name" not in tags: log.debug( f"subalert msg-id is subgift, but missing display-name: {tags}" ) return with DBManager.create_session_scope() as db_session: receiver_id = tags["msg-param-recipient-id"] receiver_login = tags["msg-param-recipient-user-name"] receiver_name = tags["msg-param-recipient-display-name"] receiver = User.from_basics( db_session, UserBasics(receiver_id, receiver_login, receiver_name)) if num_months > 1: # Resub self.on_resub(receiver, num_months, tags["msg-param-sub-plan"], tags["display-name"], substreak_count) HandlerManager.trigger("on_user_resub", user=receiver, num_months=num_months) else: # New sub self.on_new_sub(receiver, tags["msg-param-sub-plan"], tags["display-name"]) HandlerManager.trigger("on_user_sub", user=receiver) elif tags["msg-id"] == "sub": if "msg-param-sub-plan" not in tags: log.debug( f"subalert msg-id is sub, but missing msg-param-sub-plan: {tags}" ) return self.on_new_sub(source, tags["msg-param-sub-plan"]) HandlerManager.trigger("on_user_sub", user=source) elif tags["msg-id"] == "giftpaidupgrade": self.on_gift_upgrade(source) elif tags["msg-id"] == "extendsub": self.on_extend_sub(source) else: log.debug(f"Unhandled msg-id: {tags['msg-id']} - tags: {tags}")
def authorized(): try: resp = twitch.authorized_response() except OAuthException as e: log.error(e) log.exception("An exception was caught while authorizing") next_url = get_next_url(request, "state") return redirect(next_url) except Exception as e: log.error(e) log.exception("Unhandled exception while authorizing") return render_template("login_error.html") if resp is None: if "error" in request.args and "error_description" in request.args: log.warning(f"Access denied: reason={request.args['error']}, error={request.args['error_description']}") next_url = get_next_url(request, "state") return redirect(next_url) elif type(resp) is OAuthException: log.warning(resp.message) log.warning(resp.data) log.warning(resp.type) next_url = get_next_url(request, "state") return redirect(next_url) session["twitch_token"] = (resp["access_token"],) session["twitch_token_expire"] = time.time() + resp["expires_in"] * 0.75 me_api_response = twitch.get("users") if len(me_api_response.data["data"]) < 1: return render_template("login_error.html") with DBManager.create_session_scope(expire_on_commit=False) as db_session: me = User.from_basics( db_session, UserBasics( me_api_response.data["data"][0]["id"], me_api_response.data["data"][0]["login"], me_api_response.data["data"][0]["display_name"], ), ) session["user"] = me.jsonify() # bot login if me.login == app.bot_config["main"]["nickname"].lower(): redis = RedisManager.get() token_json = UserAccessToken.from_api_response(resp).jsonify() redis.set(f"authentication:user-access-token:{me.id}", json.dumps(token_json)) log.info("Successfully updated bot token in redis") # streamer login if me.login == app.bot_config["main"]["streamer"].lower(): # there's a good chance the streamer will later log in using the normal login button. # we only update their access token if the returned scope containes the special scopes requested # in /streamer_login # We use < to say "if the granted scope is a proper subset of the required scopes", this can be case # for example when the bot is running in its own channel and you use /bot_login, # then the granted scopes will be a superset of the scopes needed for the streamer. # By doing this, both the streamer and bot token will be set if you complete /bot_login with the bot # account, and if the bot is running in its own channel. if set(resp["scope"]) < set(streamer_scopes): log.info("Streamer logged in but not all scopes present, will not update streamer token") else: redis = RedisManager.get() token_json = UserAccessToken.from_api_response(resp).jsonify() redis.set(f"authentication:user-access-token:{me.id}", json.dumps(token_json)) log.info("Successfully updated streamer token in redis") next_url = get_next_url(request, "state") return redirect(next_url)
def get_user_basics_by_id(self, user_id: str) -> Optional[UserBasics]: user_data = self._get_user_data_by_id(user_id) if user_data is None: return None return UserBasics(user_data["id"], user_data["login"], user_data["display_name"])