From d5020890fd7cfe55307b94c04f59d0c396f32677 Mon Sep 17 00:00:00 2001 From: Joe Rayhawk Date: Sat, 6 Aug 2022 06:17:33 -0700 Subject: bungmobott: add "uptime", profile users on entrance, assorted fixes --- crystal/bungmobott.cr | 122 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 21 deletions(-) (limited to 'crystal') diff --git a/crystal/bungmobott.cr b/crystal/bungmobott.cr index 396b5db..bbaac50 100755 --- a/crystal/bungmobott.cr +++ b/crystal/bungmobott.cr @@ -100,9 +100,40 @@ end obsipc = Channel( String ).new ircipc = Channel( Tuple( String, String ) ).new t2sipc = Channel( Tuple( String, String ) ).new +twitchipc = Channel( Tuple( String, Union( String, UInt64 ) ) ).new + +# Twitch API request handling thread +spawn do + loop do + begin + while twitchtuple = twitchipc.receive + cmd, arg = [ *twitchtuple ] + case cmd + when "get_user" + userinfo = JSON.parse( client.get_user( arg.to_u64 ) )["data"][0] + pp userinfo + unless userinfo["broadcaster_type"].as_s.blank? + puts "\033[38;5;12m#{userinfo["login"]} is #{userinfo["broadcaster_type"]}\033[0m" + end + userage = ( Time.utc.to_unix - Time::Format::RFC_3339.parse( userinfo["created_at"].as_s ).to_unix ) + if ( userage - 172800 ) < 0 + puts "\033[38;5;1m#{userinfo["login"]}'s account is #{((172800 - userage)/60/60).to_i64} hours old.\033[0m" + end + when "get_followers" + followers = JSON.parse( client.get_user_follows( to: arg.to_u64 ) )["total"].as_i64 + if followers > 500 + puts "\033[38;5;2m#{followers} followers\033[0m" + end + end + end + end + end +end + snifflast = Int64.new(0) + def urbandef( term : String ) #http://api.urbandictionary.com/v0/define?term=waifu client = HTTP::Client.new( "api.urbandictionary.com" ) @@ -141,7 +172,11 @@ def userlog( ircipc : Channel, settings : Hash(String, String), message : FastIR end basedir = settings["statedir"] userdir = basedir + "/uids/" + uid - lastseen = File.info( userdir ).modification_time.to_unix + if File.directory?( userdir ) + lastseen = File.info( userdir ).modification_time.to_unix + else + lastseen = 0 + end Dir.mkdir_p( basedir + "/names" ) Dir.mkdir_p( userdir + "/names" ) File.touch( userdir ) @@ -215,6 +250,12 @@ def t2s( t2sipc : Channel, settings : Hash(String, String), userdir : String, ch { /\%([^ ])/, " percent sign \\1"}, { /!([^ ])/, " tchik \\1"}, { /([^ ])\$/, "\\1 dollar sign "}, + { /\(/, " open paren "}, + { /\)/, " close paren "}, + { /\{/, " open curly bracket "}, + { /\}/, " close curly bracket "}, + { /\[/, " open square bracket "}, + { /\]/, " close square bracket "}, { /0/, " zero " }, { /1/, " one " }, { /2/, " two " }, @@ -373,6 +414,9 @@ end lastvoice = Array(String).new +#streamstatus = Hash(String, Union( Bool, Float64, Int64, UInt64, String ) ).new +streamstatus = Hash(String, JSON::Any).new + # Put tts stuff into the same thread so each playback blocks the next spawn do loop do @@ -477,7 +521,6 @@ spawn do request["item"] = source if ( match = msg.match( /^\x10source ([a-z0-9-_]+) (true|false)/ ) ) request["visible"] = ( match[2] == "true" ) - obs_pubsub.send( request.to_json ) elsif ( match = msg.match( /^\x10source ([a-z0-9-_]+)/ ) ) pp scenes[scene][source]["render"] request["visible"] = ( scenes[scene][source]["render"]? != true ) @@ -492,8 +535,20 @@ spawn do request["item"] = source end end - obs_pubsub.send( request.to_json ) end + obs_pubsub.send( request.to_json ) + #if scene == currentscene + request = Hash( String, String | Bool ).new + request["request-type"] = "SetPreviewScene" + request["message-id"] = "SetPreviewScene" + request["scene-name"] = currentscene + obs_pubsub.send( request.to_json ) + request = Hash( String, String ).new + request["request-type"] = "TransitionToProgram" + request["message-id"] = "TransitionToProgram" + obs_pubsub.send( request.to_json ) + + #end elsif ( match = msg.match( /^\x10source/ ) ) request = Hash( String, String ){ "request-type" => "GetCurrentScene", @@ -515,6 +570,7 @@ spawn do end case json["update-type"]? when "StreamStatus" # these are a bit noisy, + streamstatus = json next # so skip them when "SwitchScenes" ircipc.send( { "#" + settings["channel"], "| obs: switched scene to " + ( json["scene-name"]?.as_s? || "unknown" ) } ) @@ -524,17 +580,18 @@ spawn do pp json source = json["sourceName"].as_s sources = reversesource( scenes, currentscene ) - scene = sources[source] - if scenes[scene][source]["render"] == true - request = Hash( String, String | Bool ){ - "request-type" => "SetSceneItemProperties", - "message-id" => "SetSceneItemProperties", - "scene-name" => scene, - "item" => source, - "visible" => false - } - ircipc.send( { "##{settings["channel"]}", "| obs: Media ended; disabling #{source}" } ) - obsipc.send( request.to_json ) + if scene = sources[source]? + if ( scenes[scene][source]["render"] == true ) && ( source =~ /^media-/ ) + request = Hash( String, String | Bool ){ + "request-type" => "SetSceneItemProperties", + "message-id" => "SetSceneItemProperties", + "scene-name" => scene, + "item" => source, + "visible" => false + } + ircipc.send( { "##{settings["channel"]}", "| obs: Media ended; disabling #{source}" } ) + obsipc.send( request.to_json ) + end end # If we want to start deleting temporary media sources? # if ( ( source =~ /^media-/ ) && ( scene !~ /^meta/ ) ) @@ -651,8 +708,20 @@ loop do spawn do next unless ( userlogreturn = userlog( ircipc, settings, message ) ) chatuser, uid, userdir, lastseen = userlogreturn - # play random fanfare if available. + if ( t2sreturn = t2s( t2sipc, settings, userdir, chatuser, message.params[1] ) ) + lastvoice.insert( 0, t2sreturn ) + lastvoice = lastvoice[0..4] + end + # Have we seen this user lately? if ( ( Time.utc.to_unix - lastseen ) >= 14400 ) + twitchipc.send( { "get_user", uid.to_u64 } ) + twitchipc.send( { "get_followers", uid.to_u64 } ) + prevnames = Array( String ).new + if ( prevnames = Dir.children( settings["statedir"] + "/uids/" + uid + "/names" ) ) && ( prevnames.size > 1 ) + prevnames.delete( chatuser ) + puts "\033[38;5;14m#{chatuser} previous names: #{prevnames.join(", ")}\033[0m" + end + # play random fanfare if available. {% if flag?(:windows) %} # This file hierarchy gets manually set up for now. # Maybe someday let mods do something like: @@ -664,10 +733,6 @@ loop do t2smsg( settings, "fanfare #{uid} #{chatuser}" ) {% end %} end - if ( t2sreturn = t2s( t2sipc, settings, userdir, chatuser, message.params[1] ) ) - lastvoice.insert( 0, t2sreturn ) - lastvoice = lastvoice[0..4] - end next unless ( ( match = message.params[1].match(/^ *!([A-Za-z]+) (([a-zA-Z0-9= _\:,.&'\/?;\\\(\)\[\]+\-]|!)+)/) || message.params[1].match(/^ *!([A-Za-z]+)/) ) ) cmd = match[1] own = ( message.tags["room-id"] == message.tags["user-id"] ) @@ -744,13 +809,21 @@ loop do when 3 else end - elsif ( ( cmd =~ /^scene$/ ) && ( mod || own ) ) + elsif ( cmd =~ /^uptime$/ ) + ircipc.send( { "##{settings["channel"]}", "| #{streamstatus["stream-timecode"].as_s[0..7]} Usage: #{streamstatus["cpu-usage"].as_f.to_i64}% #{streamstatus["memory-usage"].as_f.to_i64}MiB #{streamstatus["kbits-per-sec"].as_i64}kbps Frame losses: #{streamstatus["render-missed-frames"].as_i64} #{streamstatus["num-dropped-frames"].as_i64} #{streamstatus["output-skipped-frames"].as_i64}" } ) + # !newimage [name] [url] (random|top|bottom|left|right|center) + # download url, verify mimetype with libmagic, duplicate existing medialoop source, change "file" SourceSetting + elsif ( ( cmd =~ /^sourcesettings$/ ) && ( mod || own || vip ) ) + if ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ ) + obsipc.send( "{ \"request-type\": \"GetSourceSettings\", \"message-id\": \"GetSourceSettings\", \"sourceName\": \"#{match[2]}\" }" ) + end + elsif ( ( cmd =~ /^scene$/ ) && ( mod || own || vip ) ) if ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ ) obsipc.send( "{ \"request-type\": \"SetCurrentScene\", \"message-id\": \"SetCurrentScene\", \"scene-name\": \"" + match[2] + "\" }" ) else obsipc.send( "{ \"request-type\": \"GetSceneList\", \"message-id\": \"GetSceneList\" }" ) end - elsif ( ( cmd =~ /^source$/ ) && ( mod || own ) ) + elsif ( ( cmd =~ /^source$/ ) && ( mod || own || vip ) ) request = Hash( String, String | Bool ).new if ( match[2]? ) && ( sourceargs = match[2].match( /^([a-zA-Z0-9-_]+) +(true|false)$/ ) ) obsipc.send( "\x10source #{match[2]}" ) @@ -789,6 +862,13 @@ loop do end elsif ( cmd =~ /^(metaminute|youdied)$/ ) obsipc.send( "\x10source media-#{cmd}" ) + # FIXME: This is only half-implemented + elsif ( ( cmd =~ /^(user)$/ ) && ( mod || own ) ) + if match[2]? && match[2] =~ /[0-9]+/ + twitchipc.send( { "get_user", match[2].to_u64 } ) + else + twitchipc.send( { "get_user", settings["channel_id"].to_u64 } ) + end elsif ( ( cmd =~ /^(status|title)$/ ) && ( mod || own ) ) begin if match[2]? -- cgit v1.2.3