require "http/client" require "json" require "pretty_print" require "xml" require "inotify" require "time" require "twitcr" settings = Hash(String, String).new settings["home"] = Path.home.to_s ["access_token", "channel", "channel_id", "client_id", "client_id_twitch"].each do |key| begin settings[key] = File.read( settings["home"] + "/.config/twitch/" + key ).chomp rescue IO::Error STDERR.puts "Warning: Missing " + settings["home"] + "/.config/twitch/" + key end end client = Twitcr::Client.new( settings ) def ircmsg( home : String, channel : String, msg : String) if msg !~ /(\r|\n)/ sock = Socket.unix # sock.connect Socket::UNIXAddress.new( home + "/.irssi/twitch-socket".to_s, type: Socket::Type::DGRAM ) sock.connect Socket::UNIXAddress.new( home + "/.irssi/twitch-socket".to_s ) sock.puts( "#" + channel + " | " + msg ) sock.close end end voices = Hash(String, String).new File.each_line( settings["home"] + "/voicelist" ) do |line| voices[ line.downcase ] = line end #FIXME: cache twitch results def urbandef( term : String ) #http://api.urbandictionary.com/v0/define?term=waifu client = HTTP::Client.new( "api.urbandictionary.com" ) response = client.exec( "GET", "/v0/define?term=" + term ) puts response.status_code json = JSON.parse( response.body ) return json["list"][0]["definition"].to_s.gsub( /[\[\]]/, "" ).gsub( /\n/, "" ) end def commanderroot_changelog( uid ) client = HTTP::Client.new( "twitch-tools.rootonline.de", port = 443, tls = true ) response = client.exec( "GET", "/username_changelogs_search.php?q=" + uid ) client.close puts response.status_code document = XML.parse_html( response.body ) rows = document.xpath_nodes( "/html/body/div/table/tbody/tr" ) text = Array(String).new rows.each do |row| text.push( row.first_element_child.not_nil!.next_element.not_nil!.inner_text.chomp(" ").match(/[0-9a-z_]+/).not_nil![0] + " " + row.first_element_child.not_nil!.next_element.not_nil!.next_element.not_nil!.next_element.not_nil!.inner_text.chomp(" ").match(/\d{4}-\d{2}-\d{2}/).not_nil![0] ) end text.reverse! return text end logwatcher = logwatch( settings, client, voices, settings["home"] + "/irclogs/twitch/#" + settings["channel"] + "/" + Time.local.to_s("%Y-%m-%d") + ".log".to_s ) dirwatcher = Inotify.watch( settings["home"] + "/irclogs/twitch/#" + settings["channel"] + "/" ) do | event | if event.type.to_s == "CREATE" && event.name =~ /\.log$/ # FIXME: logwatcher is wrong scope, probably should move the function boundary further into it so we still hold the watcher handle logwatcher.close puts [ event.type, event.path, event.name ].join(" ") logwatcher = logwatch( settings, client, voices, event.path.not_nil! + event.name.not_nil! ) end end def logwatch( settings, client, voices, logfile ) log = File.open( logfile ) log.seek(log.size) logwatcher = Inotify.watch( logfile ) do | event | if event.type.to_s == "MODIFY" log.read_string( log.size - log.pos ).each_line do | string | # FIXME: support old names? might get confusing with e.g. reverse5612 next unless match = string.match(/^[0-9][0-9]:[0-9][0-9] <.([a-z0-9_]+)> !([A-Za-z]+) (([a-zA-Z0-9' _\:,&.-]|!)+)/) || string.match(/^[0-9][0-9]:[0-9][0-9] <.([a-z0-9_]+)> !([A-Za-z]+)/) if match[1] == settings["channel"] # if match[2].downcase == "status" # begin # if match[3]? # json = JSON.parse( client.put_channel!( settings["channel_id"].to_u64, status: match[3] ) ) # ircmsg( settings["home"], settings["channel"], "Status is now \"#{ json["status"] }\"") # else # json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) ) # ircmsg( settings["home"], settings["channel"], "Status is currently \"#{ json["status"] }\"") # end # rescue ex # ircmsg( settings["home"], settings["channel"], "An error occurred! " + ex.message.to_s ) # end # end # if match[2].downcase == "game" # begin # if match[3]? # json = JSON.parse( client.put_channel!( settings["channel_id"].to_u64, game: match[3] ) ) # ircmsg( settings["home"], settings["channel"], "Game is now \"#{ json["game"] }\"") # else # json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) ) # ircmsg( settings["home"], settings["channel"], "Game is currently \"#{ json["game"] }\"") # end # rescue ex # ircmsg( settings["home"], settings["channel"], "An error occurred! " + ex.message.to_s ) # end # end end if match[2].downcase == "name" begin if match[3]? == nil puts match[1] arg = match[1] elsif match[3]? =~ /^([a-zA-Z0-9_]+)$/ puts match[3] arg = match[3] else ircmsg( settings["home"], settings["channel"], "Argument must be a valid Twitch username or user id." ) next end if arg =~ /^[0-9]+$/ user_id = arg.to_u64 name = client.user( user_id ).login else name = arg user_id = client.user( name ).id end # FIXME: more specific exception handling pp user_id pp name user_ctime = JSON.parse( client.get_channel( user_id ) )["created_at"].to_s.match( /\d{4}-\d{2}-\d{2}/ ).not_nil![0] history = commanderroot_changelog( user_id.to_s ) history.unshift( user_ctime ) history.unshift( user_id.to_s ) history.push( name ) puts history.join(" ") ircmsg( settings["home"], settings["channel"], history.join( " " ) ) rescue ex ircmsg( settings["home"], settings["channel"], "An error occurred! " + ex.message.to_s ) end end if match[2].downcase == "urban" begin if match[3]? arg = match[3] if arg =~ /^[a-zA-Z0-9 -]+$/ definition = urbandef( arg ) ircmsg( settings["home"], settings["channel"], definition ) else ircmsg( settings["home"], settings["channel"], "Urban Dictionary search term should consist of letters, numbers, spaces, and/or hyphens." ) end else ircmsg( settings["home"], settings["channel"], "Requires an Urban Dictionary search term" ) end rescue ex ircmsg( settings["home"], settings["channel"], "An error occurred! " + ex.message.to_s ) end end end end end return logwatcher end loop do sleep 300 end #watcher.close #log.close