<commit_before># twitch_handler.rb
#
# Author::  <NAME>

require 'twitch-api'
require_relative 'twitch/stream'
require_relative 'twitch/announce_store'
require_relative 'twitch/user_stream_store'

class TwitchHandler < CommandHandler
  feature :twitch, default_enabled: true,
                   description: 'Announce when streams are live.'

  command(:live, :live)
    .feature(:twitch).max_args(0).usage('live')
    .description("Announces that you're live and links your stream.")

  command(:whoslive, :show_live_users)
    .feature(:twitch).max_args(0).pm_enabled(false).usage('whoslive')
    .description('Lists which users in this server are live.')

  command(:twitch, :link_twitch)
    .feature(:twitch).args_range(1, 1).usage('twitch <twitch_name>')
    .description('Links the given Twitch stream.')

  command(:managestreams, :manage_streams)
    .feature(:twitch).args_range(0, 2).pm_enabled(false)
    .permissions(:manage_server).usage('managestreams [option] [argument]')
    .description('Used to manage stream announcements. Try the "help" option for more details.')

  event(:playing, :on_playing_status_change)

  def redis_name
    :twitch
  end

  def config_name
    :twitch
  end

  def live(event)
    user = event.author

    return "Doesn't look like you're live... Make sure you've linked your Twitch account to Discord." unless streaming?(user)

    get_stream_data(stream_username(user)).format_message
  end

  def show_live_users(event)
    live_users_list = live_users(event.server)

    return 'No one is live at the moment.' if live_users_list.empty?

    preamble_str = "There are currently #{live_users_list.length} users live"
    preamble_str = 'There is currently 1 user live' if live_users_list.length == 1

    preamble_str + "\n" +
      live_users_list.map { |user| "#{user.display_name}: <#{user.stream_url}>" }
                     .join("\n")
  end

  def link_twitch(_event, twitch_name)
    stream_data = get_stream_data(twitch_name)

    return "There is no channel called #{twitch_name}" if stream_data.nil?

    stream_data.format_message
  end

  def manage_streams(_event, *args)
    return manage_streams_summary if args.empty?

    case args.first
    when 'help'
      manage_streams_help
    when 'add', 'remove'
      return 'Name of User is required' if args.size == 1

      manage_stream_user(args[1], args.first.to_sym)
    when 'level'
      return 'Announcement level is required' if args.size == 1

      update_stream_announce_level(args[1])
    when 'channel'
      return 'Name of Channel is required' if args.size == 1

      update_stream_announce_channel(args[1])
    when 'disable'
      disable_stream_announcements
    else
      'Invalid option.'
    end
  end

  def on_playing_status_change(event)
    return unless [0, 1].include?(event.type)

    if event.type.zero?
      user_stream_store.clear_stream_title
      return
    end

    is_reannounce = user_stream_store.title_cached?
    stream_data = handle_playing_status_change(event)

    return if stream_data.nil?

    @bot.servers.values.each do |server|
      current_redis = server_redis(server)

      next if event.user.on(server).nil?
      next unless Omnic.features[:twitch].enabled?(current_redis)

      post_announcement(event.user, current_redis, stream_data, is_reannounce)
    end
  end

  private

  def twitch_client
    @twitch_client ||= Twitch::Client.new(client_id: config.client_id)
  end

  def announce_store
    @announce_store ||= AnnounceStore.new(server_redis)
  end

  def user_stream_store
    @user_stream_store ||= UserStreamStore.new(user_redis)
  end

  def streaming?(user)
    stream_type = user.stream_type.nil? ? 0 : user.stream_type
    stream_type = stream_type.is_a?(String) ? stream_type.to_i : stream_type

    stream_type.positive?
  end

  def live_users(server)
    server.online_members(include_idle: false, include_bots: false)
          .select { |user| streaming?(user) }
  end

  def announce_channel(announcements = announce_store)
    bot.channel(announcements.channel, @server)
  end

  def stream_username(user)
    user.stream_url.split('/').last
  end

  def manage_stream_user(user, action)
    found_user = find_user(user)

    return found_user.error if found_user.failure?

    if action == :add
      announce_store.add_user(found_user.value)
      "Stream announcements are now enabled for #{found_user.value.display_name}"
    elsif action == :remove
      announce_store.remove_user(found_user.value)
      "Stream announcements are now disabled for #{found_user.value.display_name}"
    end
  end

  def handle_playing_status_change(event)
    return nil if user_stream_store.cached_title == event.user.game

    count = 0
    stream_data = loop do
      return if count == 5

      count += 1
      stream_data = get_stream_data(stream_username(event.user))
      break stream_data if stream_data.live?

      log.debug("Twitch doesn't think the stream is live yet, sleeping for a bit then retrying.")
      sleep(30)
    end<commit_msg>Adding some logging to debug a strange blowup<commit_after># twitch_handler.rb
#
# Author::  <NAME>

require 'twitch-api'
require_relative 'twitch/stream'
require_relative 'twitch/announce_store'
require_relative 'twitch/user_stream_store'

class TwitchHandler < CommandHandler
  feature :twitch, default_enabled: true,
                   description: 'Announce when streams are live.'

  command(:live, :live)
    .feature(:twitch).max_args(0).usage('live')
    .description("Announces that you're live and links your stream.")

  command(:whoslive, :show_live_users)
    .feature(:twitch).max_args(0).pm_enabled(false).usage('whoslive')
    .description('Lists which users in this server are live.')

  command(:twitch, :link_twitch)
    .feature(:twitch).args_range(1, 1).usage('twitch <twitch_name>')
    .description('Links the given Twitch stream.')

  command(:managestreams, :manage_streams)
    .feature(:twitch).args_range(0, 2).pm_enabled(false)
    .permissions(:manage_server).usage('managestreams [option] [argument]')
    .description('Used to manage stream announcements. Try the "help" option for more details.')

  event(:playing, :on_playing_status_change)

  def redis_name
    :twitch
  end

  def config_name
    :twitch
  end

  def live(event)
    user = event.author

    return "Doesn't look like you're live... Make sure you've linked your Twitch account to Discord." unless streaming?(user)

    get_stream_data(stream_username(user)).format_message
  end

  def show_live_users(event)
    live_users_list = live_users(event.server)

    return 'No one is live at the moment.' if live_users_list.empty?

    preamble_str = "There are currently #{live_users_list.length} users live"
    preamble_str = 'There is currently 1 user live' if live_users_list.length == 1

    preamble_str + "\n" +
      live_users_list.map { |user| "#{user.display_name}: <#{user.stream_url}>" }
                     .join("\n")
  end

  def link_twitch(_event, twitch_name)
    stream_data = get_stream_data(twitch_name)

    return "There is no channel called #{twitch_name}" if stream_data.nil?

    stream_data.format_message
  end

  def manage_streams(_event, *args)
    return manage_streams_summary if args.empty?

    case args.first
    when 'help'
      manage_streams_help
    when 'add', 'remove'
      return 'Name of User is required' if args.size == 1

      manage_stream_user(args[1], args.first.to_sym)
    when 'level'
      return 'Announcement level is required' if args.size == 1

      update_stream_announce_level(args[1])
    when 'channel'
      return 'Name of Channel is required' if args.size == 1

      update_stream_announce_channel(args[1])
    when 'disable'
      disable_stream_announcements
    else
      'Invalid option.'
    end
  end

  def on_playing_status_change(event)
    return unless [0, 1].include?(event.type)

    if event.type.zero?
      user_stream_store.clear_stream_title
      return
    end

    is_reannounce = user_stream_store.title_cached?
    stream_data = handle_playing_status_change(event)

    return if stream_data.nil?

    @bot.servers.values.each do |server|
      current_redis = server_redis(server)

      next if event.user.on(server).nil?
      next unless Omnic.features[:twitch].enabled?(current_redis)

      post_announcement(event.user, current_redis, stream_data, is_reannounce)
    end
  end

  private

  def twitch_client
    @twitch_client ||= Twitch::Client.new(client_id: config.client_id)
  end

  def announce_store
    @announce_store ||= AnnounceStore.new(server_redis)
  end

  def user_stream_store
    @user_stream_store ||= UserStreamStore.new(user_redis)
  end

  def streaming?(user)
    stream_type = user.stream_type.nil? ? 0 : user.stream_type
    stream_type = stream_type.is_a?(String) ? stream_type.to_i : stream_type

    stream_type.positive?
  end

  def live_users(server)
    server.online_members(include_idle: false, include_bots: false)
          .select { |user| streaming?(user) }
  end

  def announce_channel(announcements = announce_store)
    bot.channel(announcements.channel, @server)
  end

  def stream_username(user)
    user.stream_url.split('/').last
  end

  def manage_stream_user(user, action)
    found_user = find_user(user)

    return found_user.error if found_user.failure?

    if action == :add
      announce_store.add_user(found_user.value)
      "Stream announcements are now enabled for #{found_user.value.display_name}"
    elsif action == :remove
      announce_store.remove_user(found_user.value)
      "Stream announcements are now disabled for #{found_user.value.display_name}"
    end
  end

  def handle_playing_status_change(event)
    return nil if user_stream_store.cached_title == event.user.game

    count = 0
    stream_data = loop do
      return if count == 5

      count += 1
      stream_data = get_stream_data(stream_username(event.user))
      break stream_data if stream_data.live?

      log.debug("Twitch doesn't think the stream is live yet, sleeping for a bit then retrying.")
      sleep(30)
    rescue StandardError => e
      log.error(e.full_message)
      log.error("Event Type: #{event.type}; User: #{event.user.display_name}; Game: #{event.user.game}; Stream Username: #{event.user.stream_url}")
    end
{'fraction_non_alphanumeric': 0.09910869986436736, 'fraction_numerical': 0.0042627397791125754, 'mean_word_length': 3.6604966139954853, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '486487', 'n_tokens_mistral': 3406, 'n_tokens_neox': 3268, 'n_words': 776}