def parse_all_emotes(self, message, twitch_emotes_tag=None): # Twitch Emotes twitch_emote_instances = self.parse_twitch_emotes_tag( twitch_emotes_tag, message) twitch_emote_start_indices = { instance.start for instance in twitch_emote_instances } # for the other providers, split the message by spaces # and then, if word is not a twitch emote, consider ffz channel -> bttv channel -> # ffz global -> bttv global in that order. third_party_emote_instances = [] for current_word_index, word in iterate_split_with_index( message.split(" ")): # ignore twitch emotes is_twitch_emote = current_word_index in twitch_emote_start_indices if is_twitch_emote: continue emote = self.match_word_to_emote(word) if emote is None: # this word is not an emote continue third_party_emote_instances.append( EmoteInstance(start=current_word_index, end=current_word_index + len(word), emote=emote)) all_instances = twitch_emote_instances + third_party_emote_instances all_instances.sort(key=lambda instance: instance.start) return all_instances, compute_emote_counts(all_instances)
def test_iterates_correctly() -> None: # a bcd ef generator = iterate_split_with_index(["a", "bcd", "ef"]) assert next(generator) == (0, "a") assert next(generator) == (2, "bcd") assert next(generator) == (6, "ef") with pytest.raises(StopIteration): next(generator)
def test_empty_item() -> None: # a bcd ef generator = iterate_split_with_index(["a", "", "ef"]) assert next(generator) == (0, "a") assert next(generator) == (2, "") assert next(generator) == (3, "ef") with pytest.raises(StopIteration): next(generator)
def test_zero_items() -> None: generator = iterate_split_with_index([]) with pytest.raises(StopIteration): next(generator)
def bingo_start(self, bot, source, message, event, args): if self.bingo_running: bot.say(f"{source}, a bingo is already running FailFish") return False emote_instances = args["emote_instances"] known_sets = self.make_known_sets_dict() selected_sets = set() points_reward = None unparsed_options = [] words_in_message = [s for s in message.split(" ") if len(s) > 0] if len(words_in_message) <= 0: bot.say( f"{source}, You must at least give me some emote sets or emotes to choose from! FailFish" ) return False emote_index_offset = len("!bingo start ") # we can't iterate using words_in_message here because that would mess up the accompanying index for index, word in iterate_split_with_index(message.split(" ")): if len(word) <= 0: continue # Is the current word an emote? potential_emote_instance = next( (e for e in emote_instances if e.start == index + emote_index_offset), None) if potential_emote_instance is not None: # single-emote set with the name of the emote new_set = (potential_emote_instance.emote.code, (potential_emote_instance.emote, ), True) selected_sets.add(new_set) continue # Is the current word a number? try: parsed_int = int(word) except ValueError: parsed_int = None if parsed_int is not None: # if points_reward is already set this is the second number in the message if points_reward is not None: unparsed_options.append(word) continue points_reward = parsed_int continue # Is the current word a known set? cleaned_key = remove_emotes_suffix(word).lower() if cleaned_key in known_sets: selected_sets.add(known_sets[cleaned_key]) continue unparsed_options.append(word) if len(unparsed_options) > 0: bot.say( "{}, I don't know what to do with the argument{} {} BabyRage". format( source, "" if len(unparsed_options) == 1 else "s", # pluralization join_to_sentence(['"' + s + '"' for s in unparsed_options]), )) return False default_points = self.settings["default_points"] if points_reward is None: points_reward = default_points max_points = self.settings["max_points"] if points_reward > max_points: bot.say( f"{source}, You can't start a bingo with that many points. FailFish {max_points} are allowed at most." ) return False allow_negative_bingo = self.settings["allow_negative_bingo"] if points_reward < 0 and not allow_negative_bingo: bot.say( f"{source}, You can't start a bingo with negative points. FailFish" ) return False min_points = -self.settings["max_negative_points"] if points_reward < min_points: bot.say( f"{source}, You can't start a bingo with that many negative points. FailFish {min_points} are allowed at most." ) return False if len(selected_sets) <= 0: bot.say( f"{source}, You must at least give me some emotes or emote sets to choose from! FailFish" ) return False selected_set_names = [] selected_discrete_emote_codes = [] selected_emotes = set() for set_name, set_emotes, is_discrete_emote in selected_sets: if is_discrete_emote: selected_discrete_emote_codes.append(set_name) else: selected_set_names.append(set_name) selected_emotes.update(set_emotes) correct_emote = random.choice(list(selected_emotes)) user_messages = [] if len(selected_set_names) > 0: user_messages.append(join_to_sentence(selected_set_names)) if len(selected_discrete_emote_codes) > 0: # the space at the end is so the ! from the below message doesn't stop the last emote from showing up in chat user_messages.append( f"these emotes: {' '.join(selected_discrete_emote_codes)} ") bot.me( f"A bingo has started! ThunBeast Guess the right emote to win {points_reward} points! B) Only one emote per message! Select from {' and '.join(user_messages)}!" ) log.info( f"A Bingo game has begun for {points_reward} points, correct emote is {correct_emote}" ) self.active_game = BingoGame(correct_emote, points_reward)