def _add_entrance_message(self, input, command): match = re.search(r'^@?([^ ]+) (.+)$', input) if not match: self.print(f'Usage: {command.usage}') return login = match.group(1) message = match.group(2) if message.lower() == 'none': message = None broadcaster = get_broadcaster() api = broadcaster.twitch_api user_info = api.get_user(login) if not user_info: self.print(f'User not found: {login}') return if user_info['id'] not in self._sound_data['user_sounds']: self._sound_data['user_sounds'][user_info['id']] = {} self._sound_data['user_sounds'][user_info['id']]['message'] = message self._sound_data['user_sounds'][ user_info['id']]['display_name'] = user_info['display_name'] self._sound_data['user_sounds'][ user_info['id']]['login'] = user_info['login'] self.save_module_data(self._sound_data) display_name = user_info['display_name'] self.print(f'Message added for {display_name}')
def _set_volume(self, input, command): match = re.search(r'^([^ ]+) (\d+)$', input) if not match: self.print(f'Usage: {command.usage}') return login = match.group(1) volume = int(match.group(2)) broadcaster = get_broadcaster() api = broadcaster.twitch_api user_info = api.get_user(login) if not user_info: self.print(f'User not found: {login}') return if user_info['id'] not in self._sound_data['user_sounds']: self.print( f'Welcome not configured for: {user_info["display_name"]}') return self._sound_data['user_sounds'][user_info['id']]['volume'] = volume self.save_module_data(self._sound_data) self.print(f"Volume for {user_info['display_name']} set to {volume}%")
def _list_rewards(self, input, command): if not self._channel_point_data['attachments']: self.print('No channel point redemptions configured') return b = get_broadcaster() rewards = b.twitch_api.get_rewards(b.twitch_user_id) reward_map = {x['id']: x['title'] for x in rewards} self.print('Attached channel point redemptions:') for reward_id in self._channel_point_data['attachments']: if self._channel_point_data['attachments'][reward_id].get( 'command'): command_name = "!" + self._channel_point_data['attachments'][ reward_id].get('command') else: command_name = 'Not Set' self.print( f" {reward_map.get(reward_id, '<deleted>')} - {command_name}") for message in self._channel_point_data['attachments'][ reward_id].get('message_command', {}): self.print( f" {message}: !{self._channel_point_data['attachments'][reward_id]['message_command'][message]}" )
def run(self): while self._keep_listening: if (time.time() - self.last_check > 30) and (time.time() - self.last_changed > 180): broadcaster = get_broadcaster() if broadcaster: api = TwitchAPIHelper(broadcaster.oauth_tokens) stream = api.get_stream(broadcaster.twitch_user_id) if stream: if not self.broadcast_id or self.last_check == 0: self.event_queue.put(StreamStatusEvent( stream_id = stream['id'], title = stream['title'], started_at = stream['started_at'], viewer_count = stream['viewer_count'] )) self.last_changed = time.time() self.buffer_queue.put(('STATUS', 'Stream is now live!')) self.buffer_queue.put(('DEBUG', f"Stream ID: {stream['id']}")) self.broadcast_id = stream['id'] else: if self.broadcast_id or self.last_check == 0: self.event_queue.put(StreamStatusEvent()) self.last_changed = time.time() self.buffer_queue.put(('STATUS', 'Stream is offline.')) self.broadcast_id = None self.last_check = time.time() time.sleep(1)
def user_id(self): if self._user_id is not None: return self._user_id broadcaster = get_broadcaster() user_info = broadcaster.twitch_api.get_user(self.display_name.lower()) self._user_id = user_info['id'] return self._user_id
def _set_title(self, event): if not event.message: return broadcaster = get_broadcaster() res = self.twitch_api.set_stream_title(broadcaster.twitch_user_id, event.message) if res: self.send_chat_message('Stream title set to:') self.send_chat_message(res['title']) else: self.send_chat_message('Error updating stream title')
def _set_game(self, event): if not event.message: return broadcaster = get_broadcaster() stream_info = self.twitch_api.set_stream_game( broadcaster.twitch_user_id, event.message) if stream_info: game_name = stream_info['game_name'] self.send_chat_message(f'Game set to "{game_name}"') else: self.send_chat_message('Error setting game.')
def __init__(self, event_loop, voltron): self.admin_commands = {} self.voltron = voltron self.event_loop = event_loop broadcaster = get_broadcaster() self.twitch_api = None if broadcaster: self.twitch_api = broadcaster.twitch_api self.setup() self.voltron.register_module(self)
def first_message(self, event, run_by_command=False, testing=False): handled = False if not self._stream_online and not testing: return False sound_played = False if event.user_id in self._sound_data['user_sounds']: data = self._sound_data['user_sounds'][event.user_id] if data.get('sound_file', None): sound_path = f"{self.media_directory}\\{data['sound_file']}" volume = data.get('volume', 100) if not os.path.isfile(sound_path): self.buffer_print('ERR', f'{sound_path} does not exist') else: self.play_audio(sound_path, device=self.entrance_sound_device, volume=volume) sound_played = True handled = True if data.get('message', None): self.send_chat_message(data['message'], event=event) handled = True since_alert = time.time() - self._last_alert if not sound_played and self.alert_sound_device is not None and self.alert_sound and not run_by_command and since_alert > 30: alert_path = f"{self.media_directory}\\{self.alert_sound}" if not os.path.isfile(alert_path): self.buffer_print('ERR', f'{alert_path} does not exist') else: self.play_audio(alert_path, device=self.alert_sound_device) self._last_alert = time.time() if not run_by_command: broadcaster = get_broadcaster() follow_str = "Not Following" follow_time = broadcaster.twitch_api.get_follow_time( broadcaster.twitch_user_id, event.user_id) if follow_time is not None: follow_str = f"Followed {humanize.naturaltime(follow_time)}" self.print(f'First message: {event.display_name} ({follow_str})') return handled
def save(prompt): action = prompt.lower().strip() if action == 'c': self.print('No account added') return True elif action == 'y': is_broadcaster = True elif action == 'n': is_broadcaster = False else: return False def confirm(prompt): action = prompt.lower().strip() if action == 'n': return True elif action != 'y': return False account = save_oauth( login_info[0], # oauth token login_info[1], # refresh_token login_info[2], # expires in is_broadcaster # is broadcaster ) self.print( 'Authorization successful for {user} (broadcaster={broadcaster})' .format(user=account.display_name, broadcaster=is_broadcaster)) self.update_status_text() self.get_prompt() self.voltron.reset() self.voltron.start() return True broadcaster = get_broadcaster() if broadcaster and is_broadcaster: self.update_status_text( f'Replace current broadcaster account ({broadcaster.display_name})' ) self.terminate_prompt(self.prompt_ident) self.prompt_ident = self.get_prompt('[Y]es/[N]o> ', confirm) else: return confirm('y')
def _test_welcome(self, input, command): match = re.search(r'^([^ ]+)$', input) if not match: self.print(f'Usage: {command.usage}') return login = match.group(1) broadcaster = get_broadcaster() api = broadcaster.twitch_api user_info = api.get_user(login) if not user_info: self.print(f'User not found: {login}') return event = ChatMessageEvent('', user_info['display_name'], user_info['id'], False, False, False) self.first_message(event, testing=True, run_by_command=True)
def _remove_entrance_sound(self, input, command): match = re.search(r'^([^ ]+)$', input) if not match: self.print(f'Usage: {command.usage}') return login = match.group(1) user_info = get_broadcaster().twitch_api.get_user(login) if not user_info: self.print(f'User not found: {login}') return if not user_info['id'] in self._sound_data['user_sounds'].keys(): self.print( f"No sound exists for user: {user_info['display_name']}") return del self._sound_data['user_sounds'][user_info['id']] self.save_module_data(self._sound_data) self.print(f"Sound for {user_info['display_name']} removed.")
def handle_bits(self, data): message = None m = data.get('message', None) if m: m = json.loads(m) message = m['data'] if not message: return display_name = None if not message['is_anonymous']: broadcaster = get_broadcaster() user_info = broadcaster.twitch_api.get_user(message['user_name']) if user_info: display_name = user_info['display_name'] event = BitsEvent(message.get('user_id'), message.get('user_name'), display_name, message['bits_used'], message.get('chat_message', ''), message['is_anonymous'], message.get('total_bits_used', 0)) self.event_queue.put(event)
def _attach_reward(self, input, command): b = get_broadcaster() rewards = b.twitch_api.get_rewards(b.twitch_user_id) if not rewards: self.print('No rewards set up or unable to retrive from Twitch') return rewards_list = [(x['id'], x['title']) for x in rewards] index = 1 for r in rewards_list: self.print(f"{index}. {r[1]}") index += 1 def select_reward(prompt): if prompt == 'c': self.update_status_text() return True elif not prompt.isdigit(): return False index = int(prompt) if len(rewards_list) < index or index < 0: self.print('Invalid Selection') return False selected_reward = rewards_list[index - 1] def message_selected(prompt): required_message = prompt.lower() if required_message == '': required_message = None def command_selected(prompt): if prompt == 'c': self.update_status_text() return True match = re.search(r'^!([^ ]+ ?.*)$', prompt) if not match: self.print( 'Please type a valid command beginning with !') return False command = match.group(1).strip() reward_data = self._channel_point_data['attachments'].get( selected_reward[0], {}) if required_message is None: reward_data['command'] = command else: message_map = reward_data.get('message_command', {}) message_map[required_message] = command reward_data['message_command'] = message_map self._channel_point_data['attachments'][ selected_reward[0]] = reward_data self.save_module_data(self._channel_point_data) self.print( f"{selected_reward[1]} is now attached to !{command}, message: {required_message}" ) self.update_status_text() return True self.update_status_text( f'Type !<command> to attach to {selected_reward[1]}. c to cancel.' ) self.get_prompt('Command > ', command_selected) return True self.update_status_text( f'Type message to attach to {selected_reward[1]}. Leave blank for none.' ) self.get_prompt('message > ', message_selected) return True self.update_status_text('Select reward to attach. c to cancel.') self.prompt_ident = self.get_prompt('Reward #> ', select_reward)
def _delete_reward(self, input, command): if not self._channel_point_data['attachments']: self.print('No channel point redemptions configured') return b = get_broadcaster() rewards = b.twitch_api.get_rewards(b.twitch_user_id) reward_map = {x['id']: x['title'] for x in rewards} self.print('Select reward to delete:') selection_map = {} count = 1 for reward_id in self._channel_point_data['attachments']: if self._channel_point_data['attachments'][reward_id].get( 'command'): command_name = "!" + self._channel_point_data['attachments'][ reward_id].get('command') else: command_name = 'Not Set' command = self._channel_point_data['attachments'][reward_id].get( 'command') self.print( f"{count}. {reward_map.get(reward_id, '<deleted>')} - {command_name}" ) for message in self._channel_point_data['attachments'][ reward_id].get('message_command', {}): self.print( f" {message}: !{self._channel_point_data['attachments'][reward_id]['message_command'][message]}" ) selection_map[count] = reward_id count += 1 def select_reward(input): if input.lower() == 'c': self.update_status_text() return True if not input.isdigit(): return False selection = int(input) reward_id = selection_map.get(selection) if not reward_id: self.print(f'Invalid Selection: {input}') return False def select_message(input): if input == '': selected_message = None else: selected_message = input if not selected_message in self._channel_point_data[ 'attachments'][reward_id].get( 'message_command', {}): self.print(f'No message set: {selected_message}') return False def confirm(input): command = input.lower().strip() if command == 'n': self.update_status_text() return True if command == 'y': if selected_message: del self._channel_point_data['attachments'][ reward_id]['message_command'][selected_message] self.save_module_data(self._channel_point_data) self.print( f"{reward_map.get(reward_id, '<deleted>')} successfully deleted for message {selected_message}" ) self.update_status_text() else: self._channel_point_data['attachments'][reward_id][ 'command'] = None self.save_module_data(self._channel_point_data) self.print( f"{reward_map.get(reward_id, '<deleted>')} successfully deleted" ) self.update_status_text() if not self._channel_point_data['attachments'][ reward_id].get( 'command' ) and not self._channel_point_data[ 'attachments'][reward_id].get( 'message_command'): del self._channel_point_data['attachments'][ reward_id] self.save_module_data(self._channel_point_data) return True self.update_status_text( f"Delete {reward_map.get(reward_id, '<deleted>')}?") self.terminate_prompt(self.prompt_ident) self.prompt_ident = self.get_prompt('[Y]es/[N]o > ', confirm) self.update_status_text( 'Message attachment to remove. (leave blank for none)') self.terminate_prompt(self.prompt_ident) self.prompt_ident = self.get_prompt('Message > ', select_message) self.update_status_text( 'Select channel point redemption to delete. c to cancel') self.prompt_ident = self.get_prompt('Reward #> ', select_reward)
def broadcaster(self): if not self._broadcaster: self._broadcaster = get_broadcaster() return self._broadcaster