summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Rayhawk <jrayhawk+git@omgwallhack.org>2024-02-24 08:20:29 -0800
committerJoe Rayhawk <jrayhawk@fairlystable.org>2024-02-27 03:14:29 -0800
commit4c52796a73cfb981892a17eda3b570720d57794f (patch)
treeb111c50232281b3db600527a9cce2b745891bf28
parent82e1c8ecf074fe14de48ba6170ab948706a17eb7 (diff)
downloadtwitchtools-4c52796a73cfb981892a17eda3b570720d57794f.tar.gz
twitchtools-4c52796a73cfb981892a17eda3b570720d57794f.zip
crystal/tcpsocket: port over functions from old bungmobott
-rw-r--r--crystal/tcpsocket.cr530
1 files changed, 280 insertions, 250 deletions
diff --git a/crystal/tcpsocket.cr b/crystal/tcpsocket.cr
index a330aaf..a7d1e8a 100644
--- a/crystal/tcpsocket.cr
+++ b/crystal/tcpsocket.cr
@@ -40,6 +40,36 @@ class OpenSSL::SSL::Socket::Client
end
end
+# Say() in all available primary channels
+macro say_all_self_chan( text )
+ if fibers["Twitch::IRC"]?
+ say( "twitch", config.chat_user.not_nil!.twitch.not_nil!, {{text}} )
+ elsif fibers["BungmoBott::Socket client"]? &&
+ say( "twitch_remote", config.chat_user.not_nil!.twitch.not_nil!, {{text}} )
+ end
+ # FIXME: Maybe use config.join_channels.gamesurge[0]? think about this later
+ if fibers["GameSurge::IRC"]?
+ say( "gamesurge", config.chat_user.not_nil!.gamesurge.not_nil!, {{text}} )
+ elsif fibers["BungmoBott::Socket client"]?
+ say( "gamesurge_remote", config.chat_user.not_nil!.gamesurge.not_nil!, {{text}} )
+ end
+end
+
+# IRC say
+macro say( service, channel, text )
+#def say( ipc : Channel( Tuple( String, String ) ), channel : String, text : String )
+ case {{service}}
+ when "twitch"
+ twitchircipc.send( { "#" + {{channel}}, {{text}} } )
+ when "gamesurge"
+ ircipc.send( { "#" + {{channel}}, {{text}} } )
+ when "twitch_remote"
+ bbscliipc.send( "say twitch " + {{text}} )
+ when "gamesurge_remote"
+ bbscliipc.send( "say gamesurge " + {{text}} )
+ end
+end
+
macro testrefuser2uid( path )
{% if flag?(:windows) %}
File.exists?( {{path}} ) && ( File.read( {{ path }} ) =~ /^[0-9]+$/ )
@@ -156,6 +186,7 @@ def obstemporarymediacreate( obs : OBS::WebSocket, sname : String, iname, path :
}
response = obs.scenes[sname].createinput( iname, "ffmpeg_source", isettings )
# Skip ORM stuff and configure the SceneItem as fast as we possibly can
+ # FIXME: start with ?sceneItemEnabled false to give us time to SetSceneItemTransform
if ( rdata = response["responseData"]? ) && ( goodtransform = obs.sources.last_known_real_transform?( iname ) )
siid = rdata["sceneItemId"].as_i64
obs.send( OBS.req( "SetSceneItemTransform", JSON.parse( { "sceneName" => sname, "sceneItemId" => siid, "sceneItemTransform" => { "positionX" => goodtransform.to_h["positionX"], "positionY" => goodtransform.to_h["positionY"] } }.to_json ) ) )
@@ -224,8 +255,16 @@ mss : Bool
mss = false
{% end %}
+voices = Hash( String, String ).new
if ( mss || gcloud || aws ) && config.voice_list
text2speech = true
+ if File.exists?( config.voice_list.not_nil! )
+ File.read( config.voice_list.not_nil! ).strip.split( "\n" ).each do |voice|
+ voices[voice.downcase] = voice.strip
+ end
+ #else
+ #regeneratevoicelist()
+ end
else
text2speech = false
end
@@ -274,7 +313,7 @@ if config.obs_connect
d = json # Copy *immediately*
case d["eventType"].as_s
when "CurrentProgramSceneChanged"
- say( twitchircipc, config.chat_user.not_nil!.twitch.not_nil!, "| obs: switched scene to " + ( d["eventData"]["sceneName"]?.as_s? || "unknown" ) )
+ say_all_self_chan( "| obs: switched scene to " + ( d["eventData"]["sceneName"]?.as_s? || "unknown" ) )
when "MediaInputPlaybackEnded"
if d["eventData"]["inputName"].as_s =~ /^media-temporary-/
obs.send( OBS.req( "RemoveInput", JSON.parse({ "inputName" => d["eventData"]["inputName"].as_s }.to_json) ) )
@@ -285,7 +324,7 @@ if config.obs_connect
edata = d["eventData"]
name = obs.scenes[ edata["sceneName"].as_s ][ edata["sceneItemId"].as_i64 ].name
if name !~ /media-temporary/
- say( twitchircipc, config.chat_user.not_nil!.twitch.not_nil!, "| obs: source #{name} visibility is now #{edata["sceneItemEnabled"].as_bool}" )
+ say_all_self_chan( "| obs: source #{name} visibility is now #{edata["sceneItemEnabled"].as_bool}" )
end
when "SceneItemTransformChanged"
edata = d["eventData"]
@@ -307,13 +346,13 @@ if config.obs_connect
end
when "SourceFilterEnableStateChanged"
edata = d["eventData"]
- say( twitchircipc, config.chat_user.not_nil!.twitch.not_nil!, "| obs: source #{edata["sourceName"].as_s} filter #{edata["filterName"].as_s} visibility is currently #{edata["filterEnabled"].as_bool}" )
+ say_all_self_chan( "| obs: source #{edata["sourceName"].as_s} filter #{edata["filterName"].as_s} visibility is currently #{edata["filterEnabled"].as_bool}" )
end
end
Fiber.yield
end
rescue ex
- puts ex
+ pp ex
ensure
waitgroup.send( Fiber.current.name.not_nil! )
end
@@ -358,20 +397,21 @@ def urbandef( term : String )
return json["list"][0]["definition"].to_s.gsub( /[\[\]]/, "" ).gsub( /(\r|\n)/, " " )
end
+# FIXME: maybe break this out into separate functions later
def getvoice( voicelist : String, userdir : String, chatuser : String )
if File.exists?( userdir + "/voice" )
- voice_output = File.read( userdir + "/voice" ).chomp
+ voice_output = File.read( userdir + "/voice" ).strip
voice_setting = voice_output
else
- voice_output = File.read( voicelist ).chomp.split( "\n" ).sample( 1 )[0].chomp
+ voice_output = File.read( voicelist ).strip.split( "\n" ).sample( 1 )[0].strip
voice_setting = "random"
end
if File.exists?( userdir + "/voicesub" )
- namesub = File.read( userdir + "/voicesub" ).chomp
+ namesub = File.read( userdir + "/voicesub" ).strip
else
namesub = chatuser
end
- return( [namesub, voice_setting, voice_output ] )
+ return( [ namesub, voice_setting, voice_output ] )
end
def generatevoicelistaws( )
@@ -389,6 +429,7 @@ def generatevoicelistgcs( gcloud_token : String )
headers["Content-Type"] = "application/json; charset=utf-8"
response = HTTP::Client.exec( "GET", "https://texttospeech.googleapis.com/v1/voices?key=#{gcloud_token}", headers, nil, tls: ssl_context )
JSON.parse( response.body )["voices"].as_a.each do | v |
+ STDERR.puts( "#{v["naturalSampleRateHertz"]} #{v["languageCodes"]} #{v["name"]}" )
voices.push( v["name"].as_s )
end
return voices
@@ -418,24 +459,43 @@ def generatevoicelistwin()
end
{% end %}
-def regeneratevoicelist( defaultsettings : Hash( String, String ), aws : Bool, gcloud : Bool )
- voices = Hash(String, String).new
+macro writevoices()
+ File.write( config.voice_list.not_nil!, voices.values.sort.join("\r\n") )
+ say_all_self_chan( "| Wrote voice_list file." )
+end
+
+macro regeneratevoicelist()
if aws
- generatevoicelistaws() do | voice |
- voices[ voice.downcase ] = voice
+ generatevoicelistaws().each do | voice |
+ voices[ voice.downcase ] = voice.strip
end
+ elsif fibers["BungmoBott::Socket client"]?
+ bbscliipc.send( "awsvoicelist" )
end
- if gcloud
- generatevoicelistgcs( secrets.gcloud_token ).each do | voice |
- voices[ voice.downcase ] = voice
+ if secrets.gcloud_token
+ generatevoicelistgcs( secrets.gcloud_token.not_nil! ).each do | voice |
+ voices[ voice.downcase ] = voice.strip
end
+ elsif fibers["BungmoBott::Socket client"]?
+ bbscliipc.send( "gcsvoicelist" )
end
{% if flag?(:windows) %}
- generatevoicelistwin().each do
+ generatevoicelistwin().each do | voice |
+ voices[ voice.downcase ] = voice.strip
+ end
{% end %}
+ writevoices()
+end
- File.write( config.configdir + "/voicelist.txt", voices.values.sort.join("\r\n") )
- return voices
+def file_list( path : String ) : Array( String )
+ if File.file?( path )
+ return Array( String ){ File.realpath( path ) }
+ elsif File.directory?( path )
+ dir = Dir.new( path )
+ return dir.children.map{ | child | dir.path + child }
+ else
+ raise Exception.new("InvalidPath")
+ end
end
# TODO: add piping into mpv on POSIX
@@ -479,9 +539,9 @@ def userlog( config : BungmoBott::Config, service : String, message : FastIRC::M
unless ( ( prefix = message.prefix ) && ( chatuser = prefix.source ) )
return nil
end
- if service == "twitch"
+ if service =~ /^twitch/
if ( uid = message.tags["user-id"]? )
- basedir = config.statedir + "/" + service
+ basedir = config.statedir + "/twitch"
userdir = basedir + "/uids/" + uid
if File.directory?( userdir )
lastseen = File.info( userdir ).modification_time.to_unix
@@ -511,8 +571,8 @@ def userlog( config : BungmoBott::Config, service : String, message : FastIRC::M
STDERR.puts( "WARNING: userlog unexpectedly found message.prefix.source with no UID tag." )
return( nil )
end
- elsif( service == "gamesurge" )
- basedir = config.statedir + "/" + service
+ elsif( service =~ /^gamesurge/ )
+ basedir = config.statedir + "/gamesurge"
userdir = basedir + "/names/" + chatuser
if File.directory?( userdir )
lastseen = File.info( userdir ).modification_time.to_unix
@@ -528,14 +588,10 @@ def userlog( config : BungmoBott::Config, service : String, message : FastIRC::M
end
return ( { chatuser, uid, userdir, lastseen, oldname } )
rescue ex
- puts ex
+ pp ex
+ return nil
end
-# IRC say
-# does this function have a reason to exist?
-def say( ipc : Channel( Tuple( String, String ) ), channel : String, text : String )
- ipc.send( { "#" + channel, text } )
-end
# Currently only used in flag?(:unix)
def t2smsg( config : BungmoBott::Config, msg : String)
@@ -546,7 +602,7 @@ def t2smsg( config : BungmoBott::Config, msg : String)
sock.close
end
rescue ex
- puts ex
+ pp ex
end
def t2s( t2sipc : Channel, config : BungmoBott::Config, userdir : String, chatuser : String, text : String )
@@ -635,7 +691,7 @@ spawn name: "command_dispatch" do
chatuser, uid, userdir, lastseen, oldname = userlogreturn
# Have we seen this user lately?
if ( ( Time.utc.to_unix - lastseen ) >= 14400 )
- if service == "twitch" && uid.is_a?( UInt64 )
+ if service =~ /^twitch/ && uid.is_a?( UInt64 )
twitchapiipc.send( { "get_user", uid.to_s } )
twitchapiipc.send( { "get_followers", uid.to_s } )
prevnames = Array( String ).new
@@ -658,13 +714,13 @@ spawn name: "command_dispatch" do
# channel owner
# botowner
chanowner = ( chatuser == ircchannel )
- if service == "twitch"
+ if service =~ /^twitch/
#chanowner = ( message.tags["room-id"] == message.tags["user-id"] )
botowner = ( chatuser == config.chat_user.not_nil!.twitch )
vip = ( message.tags["badges"].to_s.matches?( /(^|,)vip\// ) )
mod = ( message.tags["mod"] == "1" )
sub = ( message.tags["subscriber"] == "1" )
- elsif service == "gamesurge"
+ elsif service =~ /^gamesurge/
botowner = ( chatuser == config.chat_user.not_nil!.gamesurge )
vip = false # FIXME: Maybe +v? FastIRC lets us see MODE changes, but does not itself track them
mod = false # FIXME: Probably +o
@@ -689,44 +745,198 @@ spawn name: "command_dispatch" do
if Regex.new( commandregex ).match( message.params[1] )
command.each do |exec| # Array
if (
- ( chanowner || ( exec.perm && exec.perm.not_nil!.includes?("any") ) ) ||
- ( botowner && ( exec.perm && exec.perm.not_nil!.includes?("owner") ) ) ||
- ( mod && ( exec.perm && exec.perm.not_nil!.includes?("mod") ) ) ||
- ( sub && ( exec.perm && exec.perm.not_nil!.includes?("sub") ) ) ||
- ( vip && ( exec.perm && exec.perm.not_nil!.includes?("vip") ) )
+ ( botowner || ( exec.perm && exec.perm.not_nil!.includes?("any") ) ) ||
+ ( chanowner && ( exec.perm && exec.perm.not_nil!.includes?("owner") ) ) ||
+ ( mod && ( exec.perm && exec.perm.not_nil!.includes?("mod") ) ) ||
+ ( sub && ( exec.perm && exec.perm.not_nil!.includes?("sub") ) ) ||
+ ( vip && ( exec.perm && exec.perm.not_nil!.includes?("vip") ) )
)
# As a matter of policy:
# BungmoBott::Socket clients can only say things in their own authenticated channel
# Direct IRC clients can say things whereever.
# FIXME: this needs to be service-specific
- if ( service == "twitch" && exec.func == "detect_rename" && uid.is_a?( UInt64 ) )
+ if ( service =~ /^twitch/ && exec.func == "detect_rename" && uid.is_a?( UInt64 ) )
unless oldname.is_a?( String )
- ircipc.send( { "##{config.chat_user.not_nil!.twitch}", "Rename detected: #{uid}: #{oldname} -> #{chatuser}" } )
+ say( service, config.chat_user.not_nil!.twitch.not_nil!, "Rename detected: #{uid}: #{oldname} -> #{chatuser}" )
end
next
end
if obs
# FIXME: better validate args
( exec.func == "obs_random_source_enable" ) && obsrandommediaenable( obs, exec.arg.not_nil![0].not_nil! ) && next
- # ( exec.func == "obs_stats" ) && obs_stats( obs )
+ if ( exec.func == "obs_stats_get" )
+ puts "Exec-ing obs_stats_get"
+ stats = obs.stats.to_h
+ ostatus = obs.outputs["adv_stream"].status.to_h
+ say( service, ircchannel, "| #{ostatus["outputTimecode"].to_s[0..7]} #{stats["activeFps"].to_s[0,2]}fps Usage: #{stats["cpuUsage"].as(Float64).to_i64}% #{stats["memoryUsage"].as(Float64).to_i64}MiB Frame losses: #{stats["outputSkippedFrames"].as(Int64)} #{stats["renderSkippedFrames"].as(Int64)}" )
+ next
+ end
+ if ( exec.func == "obs_scene_list_get" )
+ puts "Exec-ing obs_scene_list_get"
+ say( service, ircchannel, "| scenes: #{obs.scenes.to_h.keys.join(" ")}" )
+ next
+ end
+ if ( exec.func == "obs_scene_get" )
+ puts "Exec-ing obs_scene_get"
+ say( service, ircchannel, "| Current scene: #{obs.scenes.program.name}" )
+ next
+ end
+ if ( exec.func == "obs_scene_set" )
+ puts "Exec-ing obs_scene_set"
+
+ if ( match = / ([a-zA-Z0-9-_ ]+)/.match( message.params[1] ) )
+ obs.scenes[match[1]].program!
+ else
+ say( service, ircchannel, "| Could not find scene name." )
+ end
+ next
+ end
+ if ( exec.func == "obs_input_list_get" )
+ puts "Exec-ing obs_input_list_get"
+ say( service, ircchannel, "| inputs: #{obs.inputs.to_h.keys.join(" ")}" )
+ next
+ end
+ if ( exec.func == "obs_source_list_get" )
+ puts "Exec-ing obs_source_list_get"
+ say( service, ircchannel, "| current sources: #{obs.scenes.current.metascene.keys.join(" ")}" )
+ next
+ end
+ if ( exec.func == "obs_source_toggle" )
+ puts "Exec-ing obs_source_toggle"
+
+ if ( match = / ([a-zA-Z0-9-_ ]+)/.match( message.params[1] ) )
+ obs.scenes.current.metascene[match[1]][0].toggle!
+ # in studio mode, direct Scene->SceneItem toggles require a transition
+ obs.scenes.current.preview!
+ obs.transition!
+ else
+ say( service, ircchannel, "| Could not find source name." )
+ end
+ next
+ end
+ if ( exec.func == "obs_source_filters_list_get" )
+ puts "Exec-ing obs_source_filters_list_get"
+ if ( match = / ([a-zA-Z0-9-_]+)/.match( message.params[1] ) )
+ say( service, ircchannel, "| #{match[1]} filters: #{obs.sources.to_h[match[1]].filters.to_h.keys.join(" ")}" )
+ else
+ say( service, ircchannel, "| Could not match source name." )
+ end
+ next
+ end
+ if ( exec.func == "obs_source_filter_toggle" )
+ puts "Exec-ing obs_source_filter_toggle"
+ if ( match = / ([a-zA-Z0-9-_]+) ([a-zA-Z0-9-_]+)/.match( message.params[1] ) )
+ obs.sources.to_h[match[1]].filters[match[2]].toggle!
+ else
+ say( service, ircchannel, "| Could not match source and filter name to toggle." )
+ end
+ next
+ end
+ if ( exec.func == "obs_create_ephemeral_media_sources_from_path" )
+ puts "Exec-ing obs_create_ephemeral_media_sources_from_path"
+ count = 1
+ sources = file_list( exec.arg.not_nil![1].not_nil! )
+ if ( match = / ([0-9]+)/.match( message.params[1] ) )
+ count = match[1].to_i
+ if ( ( count < 1 ) || ( count > sources.size ) )
+ say( service, ircchannel, "| Ephemeral OBS source count must be between 1 and #{sources.size}" )
+ next
+ end
+ end
+ sources.sample( count ).each do |path|
+ obstemporarymediacreate( obs, exec.arg.not_nil![0].not_nil!, path.gsub(/[\/ ]/, '_').downcase, path )
+ end
+ next
+ end
+
+
end
if text2speech
if ( exec.func == "text_to_speech" )
puts "Exec-ing text_to_speech"
if ( t2sreturn = t2s( t2sipc, config, userdir, chatuser, message.params[1] ) )
- lastvoice.insert( 0, t2sreturn )
+ lastvoice.insert( 0, t2sreturn.strip )
lastvoice = lastvoice[0..4]
end
next
end
+ if ( exec.func == "tts_voice_list_generate" )
+ puts "Exec-ing " + exec.func
+ regeneratevoicelist()
+ say( service, ircchannel, "| Regenerated voicelist." )
+ next
+ end
+ if ( exec.func == "tts_last_voice" )
+ unless lastvoice.empty?
+ say( service, ircchannel, "| Last voices were " + lastvoice.join( ", " ) )
+ else
+ say( service, ircchannel, "| No voices used so far." )
+ end
+ next
+ end
+ if ( exec.func == "tts_voice_get" )
+ puts "Exec-ing tts_voice_get"
+ namesub, voice_setting, voice_output = getvoice( config.voice_list.not_nil!, userdir, chatuser )
+ say( service, config.chat_user.not_nil!.twitch.not_nil!, "| Current voice is #{voice_setting}" )
+ next
+ end
+ if ( exec.func == "tts_voice_set" )
+ puts "Exec-ing tts_voice_set"
+ if ( match = / ([a-zA-Z0-9-_]+)/.match( message.params[1] ) )
+ voice = match[1].downcase
+ if voice =~ /disabled|null|disable|none|random/
+ if File.exists?( userdir + "/voice" )
+ File.delete( userdir + "/voice" )
+ say( service, ircchannel, "| Voice for #{chatuser} is now random." )
+ else
+ say( service, ircchannel, "| Voice for #{chatuser} is already random." )
+ end
+ elsif voices.has_key?( voice.downcase )
+ csvoice = voices[voice]
+ Dir.mkdir_p( userdir )
+ File.write( userdir + "/voice", csvoice )
+ pp userdir
+ say( service, ircchannel, "| Voice for #{chatuser} is now #{File.read( userdir + "/voice" ).strip}." )
+ else
+ pp ( match )
+ say( service, ircchannel, "| Invalid voice. To see list, use !voices" )
+ end
+ else
+ say( service, ircchannel, "| tts_voice_set failed generic string match ")
+ end
+ next
+ end
+ if ( exec.func == "tts_name_get" )
+ puts "Exec-ing " + exec.func
+ if File.exists?( userdir + "/voicesub" )
+ say( service, ircchannel, "| Current name substitution is \"#{File.read( userdir + "/voicesub" ).strip}\"." )
+ else
+ say( service, ircchannel, "| Current name substitution is disabled." )
+ end
+ end
+ if ( exec.func == "tts_name_set" )
+ puts "Exec-ing tts_name_set"
+ if ( match = / ([\sa-zA-Z0-9-]+)$/.match( message.params[1] ) )
+ pp match[1]
+ voicesub = match[1].downcase
+ if voicesub =~ /^(disabled|null|disable|none)$/
+ if File.exists?( userdir + "/voicesub" )
+ File.delete( userdir + "/voicesub" )
+ say( service, ircchannel, "| Name substitution for #{chatuser} is now disabled." )
+ else
+ say( service, ircchannel, "| Name substitution for #{chatuser} is already disabled." )
+ end
+ else
+ Dir.mkdir_p( userdir )
+ File.write( userdir + "/voicesub", voicesub )
+ say( service, ircchannel, "| Name substitution for #{chatuser} is now \"#{File.read( userdir + "/voicesub" ).strip}\"." )
+ end
+ end
+ next
+ end
end
- # FIXME: add gamesurge support
if ( exec.func == "say" )
- if ( service == "twitch" )
- say( twitchircipc, config.chat_user.not_nil!.twitch.not_nil!, exec.arg.not_nil![0].not_nil! )
- elsif ( service == "gamesurge" )
- say( ircipc, config.chat_user.not_nil!.gamesurge.not_nil!, exec.arg.not_nil![0].not_nil! )
- end
+ say( service, config.chat_user.not_nil!.twitch.not_nil!, exec.arg.not_nil![0].not_nil! )
next
end
if ( exec.func == "run" )
@@ -754,6 +964,7 @@ spawn name: "command_dispatch" do
else
STDERR.puts( "WARNING: exec.func \"run_shell\" called without argument" )
end
+ next
end
STDERR.puts "WARNING: unhandled function for /#{commandregex}/: #{exec.func}"
else
@@ -772,139 +983,17 @@ spawn name: "command_dispatch" do
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]
-# if ( ( cmd =~ /^(substitute|voicesub)$/ ) && ( mod || sub ) )
-# case message.params[1].split( " " ).size
-# when 1
-# if File.exists?( userdir + "/voicesub" )
-# bot.message( "##{settings["channel"]}", "| Current name substitution is \"#{File.read( userdir + "/voicesub" )}\"." )
-# else
-# bot.message( "##{settings["channel"]}", "| Current name substitution is disabled." )
-# end
-# else
-# if match[2]?
-# voicesub = match[2].downcase
-# if voicesub =~ /^(disabled|null|disable|none)$/
-# if File.exists?( userdir + "/voicesub" )
-# File.delete( userdir + "/voicesub" )
-# bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is now disabled." )
-# else
-# bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is already disabled." )
-# end
-# else
-# Dir.mkdir_p( userdir )
-# File.write( userdir + "/voicesub", voicesub )
-# bot.message( "##{settings["channel"]}", "| Name substitution for #{chatuser} is now \"#{File.read( userdir + "/voicesub" )}\"." )
-# end
-# end
-# end
-# elsif ( ( cmd == "lastvoice" ) && ( mod || sub ) )
-# unless lastvoice.empty?
-# bot.message( "##{settings["channel"]}", "| Last voices were " + lastvoice.join( ", " ) )
-# else
-# bot.message( "##{settings["channel"]}", "| No voices used so far." )
-# end
-# elsif ( ( cmd == "regeneratevoicelist" ) && ( own ) )
-# voices = regeneratevoicelist( settings, aws, gcloud )
-# ircipc.send( { "##{settings["channel"]}", "| Regenerated voicelist." } )
-# elsif ( ( cmd =~ /^(setvoice|voice)$/ ) && ( mod || sub ) )
-# case message.params[1].split( " " ).size
-# when 1
-# namesub, voice_setting, voice_output = getvoice( config.voice_list_file, userdir, chatuser )
-# 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( "##{settings["channel"]}", "| Voice for #{chatuser} is now random." )
-# else
-# bot.message( "##{settings["channel"]}", "| Voice for #{chatuser} is already random." )
-# end
-# elsif voices.has_key?( voice )
-# csvoice = voices[voice]
-# Dir.mkdir_p( userdir )
-# File.write( userdir + "/voice", csvoice )
-# pp userdir
-# bot.message( "##{settings["channel"]}", "| Voice for #{chatuser} is now #{File.read( userdir + "/voice" )}." )
-# else
-# pp ( match )
-# bot.message( "##{settings["channel"]}", "| Invalid voice. To see list, use !voices" )
-# end
-# end
-# when 3
-# else
-# end
-# elsif ( cmd =~ /^uptime$/ )
-# stats = obs.stats.to_h
-# ostatus = obs.outputs["adv_stream"].status.to_h
-# ircipc.send( { "##{settings["channel"]}", "| #{ostatus["outputTimecode"].to_s[0..7]} #{stats["activeFps"].to_s[0,2]}fps Usage: #{stats["cpuUsage"].as(Float64).to_i64}% #{stats["memoryUsage"].as(Float64).to_i64}MiB Frame losses: #{stats["outputSkippedFrames"].as(Int64)} #{stats["renderSkippedFrames"].as(Int64)}" } )
-# # !newimage [name] [url] (random|top|bottom|left|right|center)
# # download url, verify mimetype with libmagic, duplicate existing medialoop source, change "file" SourceSetting
# elsif ( ( cmd =~ /^inputsetting(|s)$/ ) && ( mod || own || vip ) )
# if ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ )
# ircipc.send( { "##{settings["channel"]}", "| #{obs.inputs[match[2]].settings.to_h.to_s} " } )
# end
-# elsif ( ( cmd =~ /^input(|s)$/ ) && ( mod || own || vip ) )
-# ircipc.send( { "##{settings["channel"]}", "| inputs: #{obs.inputs.to_h.keys.join(" ")}" } )
-# elsif ( ( cmd =~ /^scene(|s)$/ ) && ( mod || own || vip ) )
-# if ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ )
-# obs.scenes[match[2]].program!
-# else
-# ircipc.send( { "##{settings["channel"]}", "| scenes: #{obs.scenes.to_h.keys.join(" ")}" } )
-# end
-# elsif ( ( cmd =~ /^source(|s)$/ ) && ( mod || own || vip ) )
-# request = Hash( String, String | Bool ).new
-# if ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ )
-# obs.scenes.current.metascene[match[2]][0].toggle!
-# # in studio mode, direct Scene->SceneItem toggles require a transition
-# obs.scenes.current.preview!
-# obs.transition!
-# else
-# ircipc.send( { "##{settings["channel"]}", "| current sources: #{obs.scenes.current.metascene.keys.join(" ")}" } )
-# end
-# elsif ( ( cmd =~ /^filter(|s)$/ ) && ( mod || own ) )
-# if ( match[2]? ) && ( filterargs = match[2].match( /^([a-zA-Z0-9-_]+) +([a-zA-Z0-9-_]+)/ ) )
-# obs.sources.to_h[filterargs[1]].filters[filterargs[2]].toggle!
-# elsif ( match[2]? && match[2] =~ /^[a-zA-Z0-9-_]+$/ )
-# ircipc.send( { "##{settings["channel"]}", "| #{match[2]} filters: #{obs.sources.to_h[match[2]].filters.to_h.keys.join(" ")}" } )
-# else
-# ircipc.send( { "##{settings["channel"]}", "Must provide at least one source name as argument, and optionally one filter name to toggle on or off." } )
-# end
# elsif ( cmd == "create" && ( mod || own || vip ) )
# if ( match[2]? ) && ( match[2] =~ /^([\/a-zA-Z0-9-_]+)/ )
# obstemporarymediacreate( obs, "meta-foreground", match[2], "C:/cygwin64/home/user/effects/#{match[2]}.webm" )
# else
# ircipc.send( { "##{settings["channel"]}", "Must provide at least one source name as argument." } )
# end
-# elsif ( cmd =~ /^(metaminute|youdied)$/ )
-# obsrandommediaenable( obs, "media-#{cmd}" )
-# elsif ( cmd =~ /^fart(s|)$/ ) && ( sub || mod || own || vip )
-# if effects.values.select( /^farts/ ).size > 0
-# if ( match[2]? ) && ( match[2].match( /^([0-9]+)/ ) && ( match[2].to_i > 1 ) && ( match[2].to_i <= 32 ) )
-# count = match[2].to_i
-# else
-# count = 1
-# end
-# effects.values.select( /^farts/ ).sample( count ).each do | effect |
-# obstemporarymediacreate( obs, "meta-foreground", effect.gsub(/[\/ ]/, '_').downcase, "C:/cygwin64/home/user/effects/#{effect}" )
-# end
-# else
-# puts "farts undefined"
-# end
-# elsif ( cmd =~ /^explosion(s|)$/ ) && ( sub || mod || own || vip )
-# if effects.values.select( /^explosions/ ).size > 0
-# if ( match[2]? ) && ( match[2].match( /^([0-9]+)/ ) && ( match[2].to_i > 1 ) && ( match[2].to_i <= 32 ) )
-# count = match[2].to_i
-# else
-# count = 1
-# end
-# effects.values.select( /^explosions/ ).sample( count ).each do | effect |
-# obstemporarymediacreate( obs, "meta-foreground", effect.gsub(/[\/ ]/, '_').downcase, "C:/cygwin64/home/user/effects/#{effect}" )
-# end
-# else
-# puts "explosions undefined"
-# end
# # FIXME: This is only half-implemented
# elsif ( ( cmd =~ /^(user)$/ ) && ( mod || own ) )
# if match[2]? && match[2] =~ /[a-z][a-z0-9_]+/
@@ -942,63 +1031,6 @@ spawn name: "command_dispatch" do
# else
# ircipc.send( { "##{settings["channel"]}", "| Urban Dictionary search term should consist of letters, numbers, spaces, and/or hyphens." } )
# end
-# elsif ( cmd == "matrix" )
-# effectsmsg( settings, "overlay glmatrix" )
-# elsif ( cmd =~ /juggle|juggler/ )
-# effectsmsg( settings, "overlay juggler3d" )
-# elsif ( cmd =~ /fireworks|firework/ )
-# effectsmsg( settings, "overlay fireworkx" )
-# elsif ( cmd == "pipes" )
-# if match[2]? && match[2] =~ /^(fast|faster)$/
-# effectsmsg( settings, "overlay pipes " + match[2] )
-# else
-# effectsmsg( settings, "overlay pipes" )
-# end
-# elsif ( cmd == "jellyfish" )
-# effectsmsg( settings, "overlay hydrostat" )
-# elsif ( cmd == "gluten" )
-# effectsmsg( settings, "overlay flyingtoasters" )
-# elsif ( cmd =~ /^(glsnake|glmatrix|gibson|xmatrix|flyingtoasters|moebiusgears|fireworkx|hydrostat|hypertorus|jigsaw|juggler3d|kaleidocycle|kumppa|molecule|noof|polyhedra)$/ )
-# 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( settings, "overlay #{cmd} #{match[2]}" )
-# puts "matched #{cmd} #{match[2]}"
-# elsif ( sub )
-# if ( seconds > 20 )
-# seconds=20
-# end
-# effectsmsg( settings, "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
-# puts "matched #{cmd} #{seconds} #{gltextargs[2]}"
-# else
-# if ( seconds > 5 )
-# seconds=5
-# end
-# effectsmsg( settings, "overlay #{cmd} #{seconds} #{gltextargs[2]}" )
-# puts "matched #{cmd} #{seconds} #{gltextargs[2]}"
-# end
-# elsif match[2]? && match[2] =~ /^.+$/
-# effectsmsg( settings, "overlay #{cmd} #{match[2]}" )
-# puts "matched #{cmd} #{match[2]}"
-# else
-# effectsmsg( settings, "overlay #{cmd}" )
-# puts "failed to match gltext"
-# end
-# elsif ( cmd =~ /^(cow(s|)|cowabunga|holycow$)/ )
-# if match[2]? && match[2] =~ /^([0-9])+$/
-# effectsmsg( settings, "overlay bouncingcow #{match[2]}" )
-# else
-# effectsmsg( settings, "overlay bouncingcow" )
-# end
-# elsif ( cmd == "overlay" )
-# if match[2]? && match[2] =~ /^[a-z]+$/
-# ircipc.send( { "##{settings["channel"]}", "| overlay requires an argument consisting wholly of lower case characters."} )
-# effectsmsg( settings, "overlay #{match[2]}" )
-# end
# elsif ( cmd =~ /^(shout|shoutout)$/ )
# if match[2]? && match[2] =~ /^[a-z]+$/
# ircipc.send( { "##{settings["channel"]}", "| Go check out twitch.tv/#{match[2]}"} )
@@ -1006,10 +1038,6 @@ spawn name: "command_dispatch" do
# else
# ircipc.send( { "##{settings["channel"]}", "| Missing argument."} )
# end
-# elsif ( cmd =~ /^(system|dxdiag|computer)$/ ) && ( Crystal::DESCRIPTION =~ /linux/ )
-# ircipc.send( { "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/tmp/DxDiag.txt" } )
-# elsif ( cmd == "hackerman" )
-# 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=/ ) )
@@ -1086,17 +1114,10 @@ spawn name: "command_dispatch" do
# end
# end
rescue ex
- puts ex
+ pp ex
puts ex.backtrace
- if service == "twitch"
- say( twitchircipc, config.chat_user.not_nil!.twitch.not_nil!, "An error occurred! " + ex.message.to_s )
- elsif service == "gamesurge"
- say( ircipc, config.chat_user.not_nil!.gamesurge.not_nil!, "An error occurred! " + ex.message.to_s )
- else
- puts "...also, the chat service is undefined."
- end
+ say_all_self_chan( "An error occurred! " + ex.message.to_s )
end
-
end
end
ensure
@@ -1119,7 +1140,6 @@ def ttsgcs( languagecode : String, voice : String, text : String, gcskey : Strin
headers = HTTP::Headers.new
headers["Content-Type"] = "application/json; charset=utf-8"
-
response = HTTP::Client.exec( "POST", "https://texttospeech.googleapis.com/v1/text:synthesize?key=#{gcskey}", headers, request.to_json, tls: ssl_context )
json=JSON.parse(response.body)
@@ -1198,7 +1218,7 @@ spawn name: "text2speech" do
end
end
rescue ex
- puts ex
+ pp ex
end
end
ensure
@@ -1322,7 +1342,7 @@ if ( secrets.twitch_access_token && config.chat_user.not_nil!.twitch && config.j
pp message
pp message.params
rescue ex
- puts ex
+ pp ex
#twitchircipc.send( { "##{config.channel}", "An error occurred! " + ex.message.to_s } )
# Maybe send all error messages out through the API? Have to do channel->client mappings, though.
end
@@ -1441,7 +1461,7 @@ if ( secrets.gamesurge_password && config.chat_user.not_nil!.gamesurge && config
# ircipc.send( { "##{settings["channel"]}", "| https://bungmonkey.omgwallhack.org/tmp/DxDiag.txt" } )
# end
rescue ex
- puts ex
+ pp ex
ircipc.send( { "##{config.chat_user.not_nil!.gamesurge.not_nil!}", "An error occurred! " + ex.message.to_s } )
end
end
@@ -1490,7 +1510,7 @@ if config.bungmobott_connect
negotiated = true
#ssl_socket.puts( "say twitch #{user} test" )
elsif ( match = message.match( /^msg (twitch|gamesurge)/ ) )
- commandircipc.send( { match[1], FastIRC.parse_line( message.split(" ")[2..].join(" ") ) } )
+ commandircipc.send( { "#{match[1]}_remote", FastIRC.parse_line( message.split(" ")[2..].join(" ") ) } )
elsif ( match = message.match( /^awst2s ([0-9]+)/ ) )
datasize = match[1].to_u32
audiodata = Bytes.new( datasize )
@@ -1501,6 +1521,16 @@ if config.bungmobott_connect
audiodata = Bytes.new( datasize )
ssl_socket.fill_read( audiodata )
playaudiodata( config.tempdir, audiodata )
+ elsif ( match = message.match( /^awsvoicelist (.+)$/ ) )
+ match[1].split(" ").each do | voice |
+ voices[voice.downcase] = voice
+ end
+ writevoices()
+ elsif ( match = message.match( /^gcsvoicelist (.+)$/ ) )
+ match[1].split(" ").each do | voice |
+ voices[voice.downcase] = voice
+ end
+ writevoices()
end
end
end
@@ -1603,7 +1633,7 @@ if config.bungmobott_listen
if ( gcloud_token = secrets.gcloud_token ).is_a?( String )
if ( match = message.match( /^gcsvoicelist$/i ) )
client.puts "gcsvoicelist " + generatevoicelistgcs( ( gcloud_token ) ).join(" ")
- elsif ( match = message.match( /^gcst2s (([a-zA-Z]{2,3}-[a-zA-Z]{2})[a-zA-Z-]+) (.+)/i ) )
+ elsif ( match = message.match( /^gcst2s (([a-zA-Z]{2,3}-[a-zA-Z]{2})[a-zA-Z0-9-]+) (.+)/i ) )
mp3data = ttsgcs( match[2], match[1], match[3], gcloud_token )
client.puts "gcst2s #{mp3data.size}"
STDOUT.puts "SENT: gcst2s #{mp3data.size}"
@@ -1613,8 +1643,8 @@ if config.bungmobott_listen
else
client.puts "ERROR: gcloud_token missing, gcs commands disabled."
end
- elsif ( match = message.match( /^say twitch (.+)/i ) )
- say( twitchircipc, connections[client]["user"], match[1] )
+ elsif ( match = message.match( /^say (twitch|gamesurge) (.+)/i ) )
+ say( match[1], connections[client]["user"], match[2] )
elsif ( message =~ /testchannelsubs/ )
#commandircipc.send( "testchannelsubs" )
end
@@ -1646,10 +1676,10 @@ if config.bungmobott_listen
end
end
rescue ex : IO::Error
- puts ex
+ pp ex
next
rescue ex
- puts ex
+ pp ex
next
ensure
connections.delete( client )
@@ -1660,7 +1690,7 @@ if config.bungmobott_listen
end
end
rescue ex
- puts ex
+ pp ex
ensure
waitgroup.send( Fiber.current.name.not_nil! )
end