summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Rayhawk <jrayhawk+git@omgwallhack.org>2022-07-03 23:06:30 -0700
committerJoe Rayhawk <jrayhawk+git@omgwallhack.org>2022-07-03 23:06:30 -0700
commit11667811c444f4721f06efed4407069f24e79df0 (patch)
tree64e427a4ef5241ed1c75860280cd96ba8da01ba5
parent681d1ff924653bf618e0b7bada80fc8dc631733c (diff)
downloadtwitchtools-11667811c444f4721f06efed4407069f24e79df0.tar.gz
twitchtools-11667811c444f4721f06efed4407069f24e79df0.zip
crystal/irc.cr: Windows compatibility and general improvements to parameterization
-rw-r--r--crystal/irc.cr490
1 files changed, 354 insertions, 136 deletions
diff --git a/crystal/irc.cr b/crystal/irc.cr
index 5d2283c..9ac7e8b 100644
--- a/crystal/irc.cr
+++ b/crystal/irc.cr
@@ -15,15 +15,37 @@ end
settings = Hash(String, String).new
+settings["configdir"] = Path.home./("/.config/bungmobott/").to_s
+settings["statedir"] = Path.home./("/.local/state/bungmobott/").to_s
+
+if ENV["LOCALAPPDATA"]?
+ settings["configdir"] = Path.windows( ENV["LOCALAPPDATA"] + "\\bungmobott\\" ).to_s
+ settings["statedir"] = Path.windows( ENV["LOCALAPPDATA"] + "\\bungmobott\\state\\" ).to_s
+end
+
+ENV["XDG_CONFIG_HOME"]? && ( settings["configdir"] = ENV["XDG_CONFIG_HOME"] + "/bungmobott/" )
+#ENV["XDG_DATA_HOME"]? && ( settings["datadir"] = ENV["XDG_DATA_HOME"] ) # unused?
+ENV["XDG_STATE_HOME"]? && ( settings["statedir"] = ENV["XDG_STATE_HOME"] + "/bungmobott/" )
+
+Dir.mkdir_p( settings["configdir"] )
+Dir.mkdir_p( settings["statedir"] )
+
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
+ settings[key] = File.read( settings["configdir"] + key ).chomp
rescue IO::Error
- STDERR.puts "Warning: Missing " + settings["home"] + "/.config/twitch/" + key
+ STDERR.puts "Warning: Missing " + settings["configdir"] + key
end
end
+if File.exists?( settings["configdir"] + "chatuser" )
+ File.read( settings["configdir"] + "chat_user" ).chomp
+else
+ STDERR.puts "Warning: Missing " + settings["configdir"] + "chat_user; using configured channel instead."
+ settings["chat_user"] = settings["channel"]
+end
+
obsipc = Channel( String ).new
ircipc = Channel( Tuple( String, String ) ).new
@@ -40,65 +62,65 @@ def urbandef( term : String )
return json["list"][0]["definition"].to_s.gsub( /[\[\]]/, "" ).gsub( /\n/, "" )
end
-def ircmsg( home : String, channel : String, msg : String)
- if msg !~ /(\r|\n)/
- sock = Socket.unix
+#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.connect Socket::UNIXAddress.new( home + "/.irssi/twitch-socket".to_s )
+# sock.puts( "#" + channel + " " + msg )
+# sock.close
+# end
+#end
+
+def t2smsg( settings : Hash(String, String), msg : String)
+ if File.exists?( settings["statedir"] + "/.t2s.sock" )
+ sock = Socket.unix
+ sock.connect Socket::UNIXAddress.new( settings["statedir"] + "/.t2s.sock" )
+ sock.puts( msg )
sock.close
end
-end
-
-def t2smsg( msg : String)
- sock = Socket.unix
- sock.connect Socket::UNIXAddress.new( ENV["HOME"] + "/.t2s.sock" )
- sock.puts( msg )
- sock.close
rescue ex
puts ex
end
-def effectsmsg( msg : String )
- sock = Socket.unix
- sock.connect Socket::UNIXAddress.new( ENV["HOME"] + "/.effects.sock" )
- sock.puts( msg )
- sock.close
+def effectsmsg( settings : Hash(String, String), msg : String )
+ if File.exists?( settings["statedir"] + "/.effects.sock" )
+ sock = Socket.unix
+ sock.connect Socket::UNIXAddress.new( settings["statedir"] + "/.effects.sock" )
+ sock.puts( msg )
+ sock.close
+ end
rescue ex
puts ex
end
-def userlog( settings : Hash(String, String), message : FastIRC::Message )
+def userlog( ircipc : Channel, settings : Hash(String, String), message : FastIRC::Message )
unless ( ( prefix = message.prefix ) && ( chatuser = prefix.source ) && ( uid = message.tags["user-id"]? ) )
return nil
end
- basedir = settings["home"] + "/.cache/twitchtools"
+ basedir = settings["statedir"]
userdir = basedir + "/uids/" + uid
- unless File.directory?( userdir )
- Dir.mkdir( userdir )
- end
- unless File.directory?( userdir + "/names" )
- Dir.mkdir( userdir + "/names" )
- end
- unless File.symlink?( userdir + "/names/" + chatuser )
- namelatest = ""
- datelatest = Time::UNIX_EPOCH
- Dir.each_child( userdir + "/names/" ) do |name|
- namedate = File.info( userdir + "/names/" + name ).modification_time
- if namedate > datelatest
- namelatest = name
- datelatest = namedate
- end
+ Dir.mkdir_p( basedir + "/names" )
+ Dir.mkdir_p( userdir + "/names" )
+ unless testrefuser2uid( userdir + "/names/" + chatuser )
+ namelatest = ""
+ datelatest = Time::UNIX_EPOCH
+ Dir.each_child( userdir + "/names/" ) do |name|
+ namedate = File.info( userdir + "/names/" + name ).modification_time
+ if namedate > datelatest
+ namelatest = name
+ datelatest = namedate
end
- unless namelatest.empty?
- ircmsg( settings["home"], settings["channel"], "Rename detected: #{uid}: #{namelatest} -> #{chatuser}" )
- end
- File.symlink( "../", userdir + "/names/" + chatuser )
end
- unless File.symlink?( basedir + "/names/" + chatuser )
- File.symlink( "../uids/" + uid, basedir + "/names/" + chatuser )
+ unless namelatest.empty?
+ ircipc.send( { "##{settings["channel"]}", "Rename detected: #{uid}: #{namelatest} -> #{chatuser}" } )
end
- unless ( message.params[0] == "#bungmonkey" )
+ genrefuser2uid( userdir + "/names/" + chatuser, uid, 3 )
+ end
+ unless testrefuser2uid( basedir + "/names/" + chatuser )
+ genrefuser2uid( basedir + "/names/" + chatuser, uid, 1 )
+ end
+ unless ( message.params[0] == "##{settings["channel"]}" )
return nil
end
return ( [ chatuser, uid, userdir ] )
@@ -111,7 +133,7 @@ def getvoice( settings : Hash(String, String), userdir : String, chatuser : Stri
voice_output = File.read( userdir + "/voice" ).chomp
voice_setting = voice_output
else
- voice_output = File.read( settings["home"] + "/voicelist.txt" ).chomp.split( "\n" ).sample( 1 )[0].chomp
+ voice_output = File.read( settings["configdir"] + "/voicelist.txt" ).chomp.split( "\n" ).sample( 1 )[0].chomp
voice_setting = "random"
end
if File.exists?( userdir + "/voicesub" )
@@ -126,17 +148,134 @@ end
def t2s( settings : Hash(String, String), userdir : String, chatuser : String, text : String )
if ( text !~ /^ *(!|\|)/ )
namesub, voice_setting, voice = getvoice( settings, userdir, chatuser )
- t2stext = text.gsub( /http(s|):\/\/([a-z0-9.]+)\/[a-zA-Z0-9\/&=%-_]+/, "link to ${2}" )
- t2stext = t2stext.gsub( /rrr.+/, "rr" )
- t2smsg( "#{voice} #{namesub} #{t2stext}" )
+ subs = Array( Tuple( Regex, String ) ){
+ { /http(s|):\/\/([a-z0-9.-]+)\/[a-zA-Z0-9\/&=%-_]+/, "link to \\2" },
+ { /([^a-zA-Z0-9])-/, "\\1 dash "},
+ { /\|/, " vertical bar "},
+ { /\`/, " grave accent "},
+ { /\+/, " plus "},
+ { /×/, " multiplied by "},
+ { /=/, " equals "},
+ { /\//, " slash "},
+ { /\\/, " backslash "},
+ { /@/, " at "},
+ { /&/, " and "},
+ { />/, " greater than "},
+ { /</, " less than "},
+ { /_/, " underscore "},
+ { /\.\.\./, " dot dot dot "},
+ { /\^/, " circumflex accent "},
+ { /\#/, " octothorpe "},
+ { /:([^ ])/, " colon \\1"},
+ { /;([^ ])/, " semicolon \\1"},
+ { /\.([^ ])/, " dot \\1"},
+ { /\%([^ ])/, " percent sign \\1"},
+ { /!([^ ])/, " tchik \\1"},
+ { /([^ ])\$/, "\\1 dollar sign "},
+ { /0/, " zero " },
+ { /1/, " one " },
+ { /2/, " two " },
+ { /3/, " three " },
+ { /4/, " four " },
+ { /5/, " five " },
+ { /6/, " six " },
+ { /7/, " seven " },
+ { /8/, " eight " },
+ { /9/, " nine " },
+ { /rrr.+/, "rr" },
+ }.each do | subtuple |
+ text = text.gsub( subtuple[0], subtuple[1] )
+ end
+ {% if flag?(:windows) %}
+ if ( match = voice.match( /^Microsoft-([A-Za-z]+)/ ) )
+ if ( match[1] =~ /Lili|Mary|Mike|Sam|Anna/ )
+ msttsvoice="Microsoft #{match[1]}"
+ else
+ msttsvoice="Microsoft #{match[1]} Desktop"
+ end
+ pp msttsvoice
+ p = Process.new( "powershell.exe", [ "-Command", "
+ echo test;
+ Add-Type -AssemblyName System.Speech;
+ $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;
+ $speak.SelectVoice(\"#{msttsvoice}\");
+ $speak.Speak($Input);
+ $speak.Finalize($Input);
+ "],
+ input: Process::Redirect::Pipe, output: STDOUT )
+ p.input.puts "#{namesub} #{text}"
+ p.input.close
+ end
+ {% elsif flag?(:unix) %}
+ t2smsg( settings, "#{voice} #{namesub} #{text}" )
+ {% end %}
return( voice )
else
return( nil )
end
end
+def reversesource( scenes : Hash( String, Hash( String, Hash( String, Int64 | Float64 | Bool | String ) ) ), currentscene : String )
+# "meta-cam-front" => {
+# "vidcap-c920" => {
+# "render" => true, "type" => "dshow_input", "x" => 0.0, "y" => 0.0
+# },
+# "gst-bungfront" => {
+# "type" => "gstreamer-source", "x" => 0.0, "y" => 0.0
+# }
+# }
+# # scenes[currentscene][source]["type"] => "scene"
+ sourcemap = Hash( String, String ).new
+ scenes[currentscene].each do | source, sourcedata |
+ # maybe make this recurse later
+ sourcemap[source.to_s] = currentscene
+ if sourcedata["type"] == "scene"
+ scenes[source.to_s].each do | metasource, metasourcedata |
+ sourcemap[metasource.to_s] = source.to_s
+ end
+ end
+ end
+ return sourcemap
+end
+
+macro testrefuser2uid( path )
+ {% if flag?(:windows) %}
+ File.exists?( {{path}} ) && ( File.read( {{ path }} ) =~ /^[0-9]+$/ )
+ {% elsif flag?(:unix) %}
+ File.symlink?( {{path}} )
+ {% end %}
+end
+
+macro genrefuser2uid( path, uid, depth )
+ {% if flag?(:windows) %}
+ File.write( {{path}}, {{uid}}.to_s )
+ {% elsif flag?(:unix) %}
+ pp "unix"
+ File.symlink( "../"*{{depth}} + "uids/#{{{uid}}}", {{path}} )
+ {% end %}
+end
+
+macro temporaryduplicate( item )
+ request = Hash( String, String | Bool ){
+ "request-type" => "SetSceneItemProperties",
+ "message-id" => "SetSceneItemProperties",
+ "scene-name" => "meta",
+ "item" => {{item}},
+ "visible" => true,
+ }
+ obsipc.send( request.to_json )
+ request = Hash( String, String | Hash( String, String ) ){
+ "request-type" => "DuplicateSceneItem",
+ "message-id" => "DuplicateSceneItem",
+ "item" => { "name" => {{item}} },
+ "fromScene" => "meta"
+ }
+ ircipc.send( { "##{settings["channel"]}", "Duplicating source #{match[2]}" } )
+ obsipc.send( request.to_json )
+end
+
voices = Hash(String, String).new
-File.each_line( settings["home"] + "/voicelist.txt" ) do |line|
+File.each_line( settings["configdir"] + "/voicelist.txt" ) do |line|
voices[ line.downcase ] = line
end
@@ -149,10 +288,36 @@ spawn do
obs_pubsub = HTTP::WebSocket.new( URI.parse( "ws://127.0.0.1:4444/" ), HTTP::Headers{"Cookie" => "SESSIONID=1234"} )
# Outgoing
+ # state
+ currentscene = "unknown"
+ # scenename => { sourcename => { property => value }
+ scenes = Hash( String, Hash( String, Hash( String, Int64 | Float64 | Bool | String ) ) ).new
spawn do
while msg = obsipc.receive
pp msg
- obs_pubsub.send( msg )
+ if ( match = msg.match( /^\x10source-toggle ([a-z0-9-_]+)/ ) )
+ source = match[1]
+ sources = reversesource( scenes, currentscene )
+ pp sources
+ request = Hash( String, String | Bool ).new
+ request["request-type"] = "SetSceneItemProperties"
+ request["message-id"] = "SetSceneItemProperties"
+ #request["request-type"] = "GetSceneItemProperties"
+ request["message-id"] = "toggle-source"
+ scene = sources[source]
+ request["scene-name"] = sources[source]
+ request["item"] = source
+ if scenes[scene][source]["render"] == true
+ request["visible"] = false
+ else
+ request["visible"] = true
+ end
+ obs_pubsub.send( request.to_json )
+ elsif ( match = msg.match( /^\x10source ([a-z0-9-_]+)/ ) )
+ # FIXME
+ else
+ obs_pubsub.send( msg )
+ end
end
end
# Incoming
@@ -168,6 +333,8 @@ spawn do
next # so skip them
when "SwitchScenes"
ircipc.send( { "#" + settings["channel"], "| obs: switched scene to " + ( json["scene-name"]?.as_s? || "unknown" ) } )
+ currentscene = json["scene-name"].as_s
+ puts "currentscene is " + currentscene
when "MediaEnded"
request = Hash( String, String | Bool ){
"request-type" => "SetSceneItemProperties",
@@ -175,8 +342,19 @@ spawn do
"item" => json["sourceName"].as_s,
"visible" => false
}
- #ircipc.send( { "##{settings["channel"]}", "Disabling #{json["sourceName"].as_s}" } )
+ ircipc.send( { "##{settings["channel"]}", "Disabling #{json["sourceName"].as_s}" } )
obsipc.send( request.to_json )
+ #"sourceName": "media-youdied"
+ puts "currentscene is " + currentscene
+ if ( ( json["sourceName"].as_s =~ /^media-/ ) && ( currentscene != "meta" ) )
+ request = Hash( String, String | Hash( String, String ) ){
+ "request-type" => "DeleteSceneItem",
+ "message-id" => "DeleteSceneItem",
+ "item" => { "name" => json["sourceName"].as_s },
+ }
+ ircipc.send( { "##{settings["channel"]}", "Deleting #{json["sourceName"].as_s}" } )
+ obsipc.send( request.to_json )
+ end
when "SourceFilterVisibilityChanged"
ircipc.send( { "##{settings["channel"]}", "| obs: source #{json["sourceName"]} filter #{json["filterName"]} visibility is now #{json["filterEnabled"]}" } )
when "SceneItemVisibilityChanged"
@@ -187,11 +365,27 @@ spawn do
print( "\n")
case json["message-id"]?
when "GetCurrentScene"
+ currentscene = json["name"].as_s
ircipc.send( { "#" + settings["channel"], "| obs: " + json["sources"].as_a.map{ |source| source["name"] }.join(", ") } )
when "GetSourceFilters"
ircipc.send( { "#" + settings["channel"], "| obs: " + json["filters"].as_a.map{ |filter| filter["name"] }.join(", ") } )
when "GetSceneList"
ircipc.send( { "#" + settings["channel"], "| obs: " + json["scenes"].as_a.map{ |scene| scene["name"] }.join(", ") } )
+ json["scenes"].as_a.each{ |scene|
+ scenes[scene["name"].as_s]? || ( scenes[scene["name"].as_s] = Hash( String, Hash( String, Int64 | Float64 | Bool | String ) ).new )
+ scene["sources"].as_a.each{ |source|
+ scenes[scene["name"].as_s][source["name"]]? || ( scenes[scene["name"].as_s][source["name"].as_s] = Hash( String, Int64 | Float64 | Bool | String ).new )
+ source["render"].as_bool != Nil && ( scenes[scene["name"].as_s][source["name"].as_s]["render"] = source["render"].as_bool )
+ source["type"].as_s? && ( scenes[scene["name"].as_s][source["name"].as_s]["type"] = source["type"].as_s )
+ source["x"].as_f? && ( scenes[scene["name"].as_s][source["name"].as_s]["x"] = source["x"].as_f )
+ source["y"].as_f? && ( scenes[scene["name"].as_s][source["name"].as_s]["y"] = source["y"].as_f )
+ source["cx"].as_i64? && ( scenes[scene["name"].as_s][source["name"].as_s]["cx"] = source["cx"].as_i64 )
+ source["cy"].as_i64? && ( scenes[scene["name"].as_s][source["name"].as_s]["cy"] = source["cy"].as_i64 )
+ source["source_cx"].as_f? && ( scenes[scene["name"].as_s][source["name"].as_s]["source_cx"] = source["source_cx"].as_f )
+ source["source_cy"].as_f? && ( scenes[scene["name"].as_s][source["name"].as_s]["source_cy"] = source["source_cy"].as_f )
+ }
+ }
+ pp scenes
when "toggle-filter"
name = json["filters"][0]["name"].as_s
visible = ( json["filters"][0]["enabled"].as_bool == false )
@@ -205,17 +399,24 @@ spawn do
obsipc.send( "{ \"request-type\": \"SetSceneItemProperties\", \"message-id\": \"SetSceneItemProperties\", \"item\": \"#{name}\", \"visible\": #{visible} }" )
end
end
+ request = Hash( String, String ){
+ "request-type" => "GetCurrentScene",
+ "message-id" => "GetCurrentScene",
+ }
+ obsipc.send( request.to_json )
+
obs_pubsub.run
- rescue ex : IO::Error
- pp ex
- ircipc.send( { "#" + settings["channel"], "obs.cr:obs: " + ex.to_s.gsub(/\r|\n/, ' ') + ": Maybe try again in 10 seconds?" } )
rescue ex : Socket::ConnectError
# these are a bit noisy
pp ex
obs_pubsub && obs_pubsub.close
+ rescue ex : IO::Error
+ pp ex
+ ircipc.send( { "#" + settings["channel"], "obs.cr:obs: " + ex.to_s.gsub(/\r|\n/, ' ') + ": Maybe try again in 10 seconds?" } )
rescue ex
- ircmsg( settings["home"], settings["channel"], "irc.cr:obs: " + ex.to_s.gsub(/\r|\n/, ' ') )
- puts ex
+ pp ex
+ pp ex.backtrace?
+ ircipc.send( { "#" + settings["channel"], "irc.cr:obs: " + ex.to_s.gsub(/\r|\n/, ' ') } )
obs_pubsub && obs_pubsub.close
end
sleep 10
@@ -227,24 +428,27 @@ end
loop do
begin
- bot = Twitch::IRC::Client.new( nick: settings["channel"], token: "oauth:" + settings["access_token"], log_mode: true )
+ bot = Twitch::IRC::Client.new( nick: settings["chat_user"], token: "oauth:" + settings["access_token"], log_mode: true )
bot.tags = [ "membership", "tags", "commands" ]
# Outgoing
+ # "Most IRC servers limit messages to 512 bytes in length, including the trailing CR-LF characters."
+ # PRIVMSG #channel message\r\n
spawn do
- while msgtuple = ircipc.receive
-bot.message( msgtuple[0], msgtuple[1][0..480] )
+ while msgtuple = ircipc.receive # why does this need to be a tuple?
+ sizelimit=( 512 - ( msgtuple[0].size + 11 ) )
+ bot.message( msgtuple[0], msgtuple[1][0..sizelimit] ) # limit size
end
end
# Create a handler to process incoming messages
bot.on_message do |message|
spawn do
- next unless ( userlogreturn = userlog( settings, message ) )
+ next unless ( userlogreturn = userlog( ircipc, settings, message ) )
chatuser, uid, userdir = userlogreturn
if ( chatuser == "pipne" ) && ( ( Time.utc.to_unix - snifflast ) >= 14400 )
snifflast = Time.utc.to_unix
- t2smsg( chatuser + " sniff null" )
+ t2smsg( settings, chatuser + " sniff null" )
end
if ( t2sreturn = t2s( settings, userdir, chatuser, message.params[1] ) )
lastvoice.insert( 0, t2sreturn )
@@ -260,9 +464,9 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
case message.params[1].split( " " ).size
when 1
if File.exists?( userdir + "/voicesub" )
- bot.message( "#bungmonkey", "| Current name substitution is \"#{File.read( userdir + "/voicesub" )}\"." )
+ bot.message( "##{settings["channel"]}", "| Current name substitution is \"#{File.read( userdir + "/voicesub" )}\"." )
else
- bot.message( "#bungmonkey", "| Current name substitution is disabled." )
+ bot.message( "##{settings["channel"]}", "| Current name substitution is disabled." )
end
else
if match[2]?
@@ -270,54 +474,54 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
if voicesub =~ /^(disabled|null|disable|none)$/
if File.exists?( userdir + "/voicesub" )
File.delete( userdir + "/voicesub" )
- bot.message( "#bungmonkey", "| Name substitution for #{chatuser} is now disabled." )
+ bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is now disabled." )
else
- bot.message( "#bungmonkey", "| Name substitution for #{chatuser} is already disabled." )
+ bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is already disabled." )
end
else
- File.directory?( userdir ) || Dir.mkdir( userdir )
+ Dir.mkdir_p( userdir )
File.write( userdir + "/voicesub", voicesub )
- bot.message( "#bungmonkey", "| Name substitution for #{chatuser} is now \"#{File.read( userdir + "/voicesub" )}\"." )
+ bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is now \"#{File.read( userdir + "/voicesub" )}\"." )
end
end
end
elsif ( cmd =~ /^(commands|help)$/ )
- bot.message( "#bungmonkey", "| https://bungmonkey.omgwallhack.org/txt/commands.txt" )
+ bot.message( "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/txt/commands.txt" )
elsif ( cmd =~ /^(dexem)$/ )
- ircipc.send( { "#bungmonkey", "| You're doing great work, Dexem!" } )
+ ircipc.send( { "##{settings["channel"]}", "| You're doing great work, Dexem!" } )
elsif ( ( cmd == "lastvoice" ) && ( mod || sub ) )
unless lastvoice.empty?
- bot.message( "#bungmonkey", "| Last voices were " + lastvoice.join( ", " ) )
+ bot.message( "##{settings["channel"]}", "| Last voices were " + lastvoice.join( ", " ) )
else
- bot.message( "#bungmonkey", "| No voices used so far." )
+ bot.message( "##{settings["channel"]}", "| No voices used so far." )
end
elsif ( ( cmd =~ /^(voices|voicelist)$/ ) && ( mod || sub ) )
- bot.message( "#bungmonkey", "| https://bungmonkey.omgwallhack.org/voicelist.txt" )
+ bot.message( "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/voicelist.txt" )
elsif ( ( cmd =~ /^(setvoice|voice)$/ ) && ( mod || sub ) )
case message.params[1].split( " " ).size
when 1
namesub, voice_setting, voice_output = getvoice( settings, userdir, chatuser )
- bot.message( "#bungmonkey", "| Current voice is #{voice_setting}" )
+ bot.message( "##{settings["channel"]}", "| Current voice is #{voice_setting}" )
when 2
if match[2]?
voice = match[2].downcase
if voice =~ /disabled|null|disable|none|random/
if File.exists?( userdir + "/voice" )
File.delete( userdir + "/voice" )
- bot.message( "#bungmonkey", "| Voice for #{chatuser} is now random." )
+ bot.message( "##{settings["channel"]}", "| Voice for #{chatuser} is now random." )
else
- bot.message( "#bungmonkey", "| Voice for #{chatuser} is already random." )
+ bot.message( "##{settings["channel"]}", "| Voice for #{chatuser} is already random." )
end
elsif voices.has_key?( voice )
csvoice = voices[voice]
- File.directory?( userdir ) || Dir.mkdir( userdir )
+ Dir.mkdir_p( userdir )
File.write( userdir + "/voice", csvoice )
pp userdir
- bot.message( "#bungmonkey", "| Voice for #{chatuser} is now #{File.read( userdir + "/voice" )}." )
+ bot.message( "##{settings["channel"]}", "| Voice for #{chatuser} is now #{File.read( userdir + "/voice" )}." )
# TODO: make separate script to print streamelements URLs to client machine
else
pp ( match )
- bot.message( "#bungmonkey", "| Invalid voice. To see list, use !voices" )
+ bot.message( "##{settings["channel"]}", "| Invalid voice. To see list, use !voices" )
end
end
when 3
@@ -332,23 +536,28 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
elsif ( ( cmd =~ /^source$/ ) && ( mod || own ) )
request = Hash( String, String | Bool ).new
if ( match[2]? ) && ( sourceargs = match[2].match( /^([a-zA-Z0-9-_]+) +(true|false)/ ) )
- request["request-type"] = "SetSceneItemProperties"
- request["message-id"] = "SetSceneItemProperties"
- request["item"] = sourceargs[1]
- sourceargs[2] == "true" && ( request["visible"] = true )
- sourceargs[2] == "false" && ( request["visible"] = false )
-
- ircipc.send( { "##{settings["channel"]}", "Setting source #{sourceargs[1]} visibility to #{sourceargs[2]}" } )
- obsipc.send( request.to_json )
+# request["request-type"] = "SetSceneItemProperties"
+# request["message-id"] = "SetSceneItemProperties"
+# request["item"] = sourceargs[1]
+# sourceargs[2] == "true" && ( request["visible"] = true )
+# sourceargs[2] == "false" && ( request["visible"] = false )
+#
+# ircipc.send( { "##{settings["channel"]}", "Setting source #{sourceargs[1]} visibility to #{sourceargs[2]}" } )
+ obsipc.send( "\x10source #{match[2]}" )
elsif ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ )
- request["request-type"] = "GetSceneItemProperties"
- request["message-id"] = "toggle-source"
- request["item"] = match[2]
- obsipc.send( request.to_json )
+ #sources = reversesource( scenes, currentscene )
+ #request["request-type"] = "SetSceneItemProperties"
+ #request["message-id"] = "SetSceneItemProperties"
+ #request["request-type"] = "GetSceneItemProperties"
+ #request["message-id"] = "toggle-source"
+ #request["item"] = match[2]
+ #obsipc.send( request.to_json )
+ obsipc.send( "\x10source-toggle #{match[2]}" )
else
- request["request-type"] = "GetCurrentScene"
- request["message-id"] = "GetCurrentScene"
- obsipc.send( request.to_json )
+# request["request-type"] = "GetCurrentScene"
+# request["message-id"] = "GetCurrentScene"
+# obsipc.send( request.to_json )
+ obsipc.send( "\x10source #{match[2]}" )
end
elsif ( ( cmd =~ /^filter$/ ) && ( mod || own ) )
request = Hash( String, String | Bool ){
@@ -375,6 +584,12 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
else
ircipc.send( { "##{settings["channel"]}", "Must provide at least one source name as argument, and optionally one filter name." } )
end
+ elsif ( cmd == "duplicate" && ( mod || own || vip ) )
+ if ( match[2]? ) && ( filterargs = match[2].match( /^([a-zA-Z0-9-_]+)/ ) )
+ temporaryduplicate( match[2] )
+ else
+ ircipc.send( { "##{settings["channel"]}", "Must provide at least one source name as argument." } )
+ end
elsif ( cmd =~ /^(metaminute|youdied)$/ )
request = Hash( String, String | Bool ).new
request["request-type"] = "SetSceneItemProperties"
@@ -393,13 +608,13 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
if match[2]?
client.put_channel!( settings["channel_id"].to_u64, title: match[2] )
json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) )
- ircmsg( settings["home"], settings["channel"], "Title is now \"#{ json["data"][0]["title"] }\"")
+ ircipc.send( { "##{settings["channel"]}", "Title is now \"#{ json["data"][0]["title"] }\""} )
else
json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) )
- ircmsg( settings["home"], settings["channel"], "| Title is currently \"#{ json["data"][0]["title"] }\"")
+ ircipc.send( { "##{settings["channel"]}", "| Title is currently \"#{ json["data"][0]["title"] }\""} )
end
rescue ex
- ircmsg( settings["home"], settings["channel"], "| An error occurred! " + ex.message.to_s )
+ ircipc.send( { "##{settings["channel"]}", "| An error occurred! " + ex.message.to_s } )
end
elsif ( ( cmd =~ /^(game|category)$/ ) && ( mod || own ) )
begin
@@ -407,85 +622,88 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
puts "2 matches"
client.put_channel!( settings["channel_id"].to_u64, game: match[2] )
json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) )
- ircmsg( settings["home"], settings["channel"], "Game is now \"#{ json["data"][0]["game_name"] }\"")
+ ircipc.send( { "##{settings["channel"]}", "Game is now \"#{ json["data"][0]["game_name"] }\""} )
else
puts "1 matches"
json = JSON.parse( client.get_channel( settings["channel_id"].to_u64 ) )
- ircmsg( settings["home"], settings["channel"], "| Game is currently \"#{ json["data"][0]["game_name"] }\"")
+ ircipc.send( { "##{settings["channel"]}", "| Game is currently \"#{ json["data"][0]["game_name"] }\""} )
end
rescue ex
- ircmsg( settings["home"], settings["channel"], "| An error occurred! " + ex.message.to_s )
+ ircipc.send( { "##{settings["channel"]}", "| An error occurred! " + ex.message.to_s } )
end
elsif ( ( cmd == "urban" ) && ( mod || own || sub || vip ) )
if match[2]? && match[2] =~ /^([a-zA-Z0-9 -])+$/
definition = urbandef( match[2] )
- ircmsg( settings["home"], settings["channel"], definition[0,400] )
+ ircipc.send( { "##{settings["channel"]}", definition[0,400] } )
else
- ircmsg( settings["home"], settings["channel"], "| Urban Dictionary search term should consist of letters, numbers, spaces, and/or hyphens." )
+ ircipc.send( { "##{settings["channel"]}", "| Urban Dictionary search term should consist of letters, numbers, spaces, and/or hyphens." } )
end
elsif ( cmd == "matrix" )
- effectsmsg( "overlay glmatrix" )
+ effectsmsg( settings, "overlay glmatrix" )
elsif ( cmd =~ /juggle|juggler/ )
- effectsmsg( "overlay juggler3d" )
+ effectsmsg( settings, "overlay juggler3d" )
elsif ( cmd =~ /fireworks|firework/ )
- effectsmsg( "overlay fireworkx" )
+ effectsmsg( settings, "overlay fireworkx" )
elsif ( cmd == "pipes" )
if match[2]? && match[2] =~ /^(fast|faster)$/
- effectsmsg( "overlay pipes " + match[2] )
+ effectsmsg( settings, "overlay pipes " + match[2] )
else
- effectsmsg( "overlay pipes" )
+ effectsmsg( settings, "overlay pipes" )
end
elsif ( cmd == "jellyfish" )
- effectsmsg( "overlay hydrostat" )
+ effectsmsg( settings, "overlay hydrostat" )
elsif ( cmd == "gluten" )
- effectsmsg( "overlay flyingtoasters" )
+ effectsmsg( settings, "overlay flyingtoasters" )
elsif ( cmd =~ /^(glsnake|glmatrix|gibson|xmatrix|flyingtoasters|moebiusgears|fireworkx|hydrostat|hypertorus|jigsaw|juggler3d|kaleidocycle|kumppa|molecule|noof|polyhedra)$/ )
- effectsmsg( "overlay " + cmd )
- elsif ( cmd =~ /gltext|cowsay|xcowsay/ )
+ effectsmsg( settings, "overlay " + cmd )
+ elsif ( cmd =~ /gltext|cowsay|xcowsay|cowfuscious/ )
+ ( cmd == "cowfuscious" ) && ( cmd = "xcowsay" )
if ( match[2]? ) && ( gltextargs = match[2].match( /^([0-9]+) +(.+)$/ ) )
seconds=UInt64.new( 1 )
seconds=gltextargs[1].to_u64
if ( own || mod || vip )
- effectsmsg( "overlay #{cmd} #{match[2]}" )
+ effectsmsg( settings, "overlay #{cmd} #{match[2]}" )
puts "matched #{cmd} #{match[2]}"
elsif ( sub )
if ( seconds > 20 )
seconds=20
end
- effectsmsg( "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
+ effectsmsg( settings, "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
puts "matched #{cmd} #{seconds} #{gltextargs[2]}"
else
if ( seconds > 5 )
seconds=5
end
- effectsmsg( "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
+ effectsmsg( settings, "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
puts "matched #{cmd} #{seconds} #{gltextargs[2]}"
end
elsif match[2]? && match[2] =~ /^.+$/
- effectsmsg( "overlay #{cmd} #{match[2]}" )
+ effectsmsg( settings, "overlay #{cmd} #{match[2]}" )
puts "matched #{cmd} #{match[2]}"
else
- effectsmsg( "overlay #{cmd}" )
+ effectsmsg( settings, "overlay #{cmd}" )
puts "failed to match gltext"
end
- elsif ( cmd =~ /cow|cowabunga|holycow/ )
+ elsif ( cmd =~ /^(cow(s|)|cowabunga|holycow$)/ )
if match[2]? && match[2] =~ /^([0-9])+$/
- effectsmsg( "overlay bouncingcow #{match[2]}" )
+ effectsmsg( settings, "overlay bouncingcow #{match[2]}" )
else
- effectsmsg( "overlay bouncingcow" )
+ effectsmsg( settings, "overlay bouncingcow" )
end
elsif ( cmd == "overlay" )
if match[2]? && match[2] =~ /^[a-z]+$/
- ircmsg( settings["home"], settings["channel"], "| overlay requires an argument consisting wholly of lower case characters.")
- effectsmsg( "overlay #{match[2]}" )
+ ircipc.send( { "##{settings["channel"]}", "| overlay requires an argument consisting wholly of lower case characters."} )
+ effectsmsg( settings, "overlay #{match[2]}" )
else
end
+ elsif ( cmd =~ /^(system|dxdiag|computer)$/ )
+ ircipc.send( { "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/tmp/DxDiag.txt" } )
elsif ( cmd == "hackerman" )
- ircmsg( settings["home"], settings["channel"], "| https://bungmonkey.omgwallhack.org/img/hackerman.jpg" )
+ ircipc.send( { "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/img/hackerman.jpg" } )
elsif ( cmd =~ /^(songrequest|sr)$/ ) && match[2]?
puts ("song detected: #{match[2]}")
if ( ( match[2] =~ /list=/ ) && ( match[2] !~ /v=/ ) )
- ircmsg( settings["home"], settings["channel"], "| Lists are not accepted.\n" )
+ ircipc.send( { "##{settings["channel"]}", "| Lists are not accepted.\n" } )
elsif Process.run( "sraddsong.sh", {match[2]} )
m = MPD::Client.new
currentsong = m.currentsong
@@ -493,9 +711,9 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
m.next
end
if ( status = m.status ) && ( playlistinfo = m.playlistinfo )
- ircmsg( settings["home"], settings["channel"], "| " + playlistinfo[ status["playlistlength"].to_i - 1 ]["file"].to_s + " added in position " + status["playlistlength"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| " + playlistinfo[ status["playlistlength"].to_i - 1 ]["file"].to_s + " added in position " + status["playlistlength"].to_s } )
else
- ircmsg( settings["home"], settings["channel"], "| A failure occured." )
+ ircipc.send( { "##{settings["channel"]}", "| A failure occured." } )
end
m.disconnect
else
@@ -503,9 +721,9 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
elsif ( cmd =~ /^current(|song)$/ )
m = MPD::Client.new
if ( currentsong = m.currentsong )
- ircmsg( settings["home"], settings["channel"], "| Currently playing: " + currentsong["file"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| Currently playing: " + currentsong["file"].to_s } )
else
- ircmsg( settings["home"], settings["channel"], "| A failure occured." )
+ ircipc.send( { "##{settings["channel"]}", "| A failure occured." } )
end
m.disconnect
elsif ( cmd =~ /^seek$/ )
@@ -515,25 +733,25 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
if ( ( musicstatus = m.status ) && ( pos = musicstatus["elapsed"].to_f.to_u64 ) )
min=( pos / 60 ).to_u64
sec=( pos % 60 ).to_u64
- ircmsg( settings["home"], settings["channel"], "| " + sprintf( "2%d:2%d", min, sec ) )
+ ircipc.send( { "##{settings["channel"]}", "| " + sprintf( "2%d:2%d", min, sec ) } )
else
- ircmsg( settings["home"], settings["channel"], "| An error occurred. " )
+ ircipc.send( { "##{settings["channel"]}", "| An error occurred. " } )
end
m.disconnect
else
- ircmsg( settings["home"], settings["channel"], "| Seek requires an argument of an absolute position in integer number of seconds, or a relative position in in signed integer number of seconds such as +60" )
+ ircipc.send( { "##{settings["channel"]}", "| Seek requires an argument of an absolute position in integer number of seconds, or a relative position in in signed integer number of seconds such as +60" } )
end
elsif ( cmd =~ /^next(|song)$/ )
m = MPD::Client.new
m.next
if ( status = m.status ) && ( status["playlistlength"].to_i > 0 )
if ( currentsong = m.nextsong )
- ircmsg( settings["home"], settings["channel"], "| Currently playing: " + currentsong["file"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| Currently playing: " + currentsong["file"].to_s } )
else
- ircmsg( settings["home"], settings["channel"], "| A failure occured." )
+ ircipc.send( { "##{settings["channel"]}", "| A failure occured." } )
end
else
- ircmsg( settings["home"], settings["channel"], "| Playlist is now empty." )
+ ircipc.send( { "##{settings["channel"]}", "| Playlist is now empty." } )
end
m.disconnect
elsif ( cmd == "followage" )
@@ -545,27 +763,27 @@ bot.message( msgtuple[0], msgtuple[1][0..480] )
puts client.user_id( args[0] ).to_s
puts client.user_id( args[1] ).to_s
puts json
- ircmsg( settings["home"], settings["channel"], "| " + json["data"][0]["followed_at"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| " + json["data"][0]["followed_at"].to_s } )
elsif args[0]?
json = JSON.parse( client.get_user_follows( from: client.user_id( args[0] ).to_u64 , to: settings["channel_id"].to_u64 ) )
puts client.user_id( args[0] ).to_s
puts json
- ircmsg( settings["home"], settings["channel"], "| " + json["data"][0]["followed_at"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| " + json["data"][0]["followed_at"].to_s } )
end
else
json = JSON.parse( client.get_user_follows( from: uid.to_u64 , to: settings["channel_id"].to_u64 ) )
puts json
- ircmsg( settings["home"], settings["channel"], "| " + json["data"][0]["followed_at"].to_s )
+ ircipc.send( { "##{settings["channel"]}", "| " + json["data"][0]["followed_at"].to_s } )
end
rescue ex
- ircmsg( settings["home"], settings["channel"], "An error occurred! " + ex.message.to_s )
+ ircipc.send( { "##{settings["channel"]}", "An error occurred! " + ex.message.to_s } )
end
end
end
end
rooms = Array( String ).new
- rooms = [ "#bungmonkey", "kr3wzz" ]
+ rooms = [ "##{settings["channel"]}" ]
# Connect to Twitch
bot.run( rooms.map{ | room | room.sub( /^#/, "") } )