require "obswebsocket" require "pretty_print" require "math" STDOUT.sync = true STDOUT.flush_on_newline = true struct Nil def as_s? self end 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 settings["tempdir"] = "/tmp/bungmobott/" ENV["TEMP"]? && ( settings["tempdir"] = "#{ENV["TEMP"]}\\bungmobott\\" ) 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"] ) Dir.mkdir_p( settings["tempdir"] ) settings["home"] = Path.home.to_s regextwitchuser = /^[0-9a-zA-Z_]+$/ obs = OBS::WebSocket.new( "ws://127.0.0.1:4455/" ) directions = Hash( String, Float64 ).new # OBS event thread spawn do evchan = Channel( JSON::Any ).new obs.eventsub_add( evchan ) while json = evchan.receive # A Fiber.yield occurs after this to make sure "json" doesn't get overwritten before we can use it. spawn do d = json # Copy *immediately* case d["eventType"].as_s when "SceneItemTransformChanged" edata = d["eventData"] puts "test 1" scenelist = obs.scenes[edata["sceneName"].as_s] puts "test 2" sceneitem = scenelist[edata["sceneItemId"].as_i64] puts "test 3" t = edata["sceneItemTransform"] if ( direction = directions[sceneitem.name]? ) spx = t["positionX" ].as_f.to_i64 spy = t["positionY" ].as_f.to_i64 sdx = t["sourceHeight"].as_f.to_i64 sdy = t["sourceWidth" ].as_f.to_i64 bx = obs.video.to_h["baseWidth" ].as(Int64 | Float64).to_i64 by = obs.video.to_h["baseHeight"].as(Int64 | Float64).to_i64 abx = bx - sdx aby = by - sdy ratio = Math.tan(direction) spxr = (aby/2 * ratio).abs if spxr > abx/2 spxr = abx/2 spyr = abx/2 * ratio elsif ratio > 0 spyr = abx/2 else # ratio < 0 spyr = abx/2 * -1 end if ( direction >= 0 ) && ( direction <= Math::PI ) nspx = spxr else # ( direction >= Math::PI ) && ( direction <= 2*Math::PI ) nspx = ( spxr * -1 ) end nspx = nspx - sdx nspy = spyr - sdy unless ( spx == nspx && spy == nspy ) sceneitem.transform( { "positionX" => nspx, "positionY" => nspy } ) end end end end Fiber.yield end end def obsrandommediaenable( obs : OBS::WebSocket, siname : String ) if ( Random.rand(3) < 2 ) obs.scenes.current.metascene[siname][0].enable! else randsiname = obs.scenes.current.metascene.keys.select( /^#{siname}/ ).sample( 1 )[0] obs.scenes.current.metascene[randsiname][0].enable! end end name=ARGV[0].sub( /.+\//, "" ).sub( /\..+/, "" ) def obsmediacreate( obs : OBS::WebSocket, sname : String, iname, path : String ) iname = "medialoop-bullshit-#{iname}" isettings = Hash( String, String | Bool | Int64 | Float64 ){ "advanced" => true, "clear_on_media_end" => true, "color_range" => 0.to_i64, "is_local_file" => true, "looping" => true, "restart_on_activate" => true, "local_file" => path, } response = obs.scenes[sname].createinput( iname, "ffmpeg_source", isettings ) # Skip object model stuff and configure the SceneItem as fast as we possibly can if ( rdata = response["responseData"]? ) && ( goodtransform = obs.sources.last_known_real_transform?( iname ) ) siid = rdata["sceneItemId"].as_i64 ENV["DISTANCE"] # percent ENV["DIRECTION"] # degrees ENV["SIZE"] # width\nheight ENV["COLORMASK"] # color/RGB(A) html color code # obs.send_sync( OBS.req( "SetSceneItemTransform", JSON.parse( { "sceneName" => sname, "sceneItemId" => siid, "sceneItemTransform" => { "positionX" => goodtransform.to_h["positionX"], "positionY" => goodtransform.to_h["positionY"] } }.to_json ) ) ) end if ( colormask = ENV["COLORMASK"].to_u32 ) obs.send_sync( OBS.req( "CreateSourceFilter", JSON.parse( { "sourceName" => iname, "filterName" => "chromakey", "filterKind" => "chroma_key_filter_v2", "filterSettings" => { "key_color_type" => "custom", "key_color" => colormask, "smoothness" => 10, "similarity" => "1" } }.to_json ) ) ) #obs.send_sync( OBS.req( "CreateSourceFilter", JSON.parse( { "sourceName" => iname, "filterName" => "colorkey", "filterKind" => "color_key_filter_v2", "filterSettings" => { "key_color_type" => "custom", "key_color" => colormask, "smoothness" => 1000 } }.to_json ) ) ) end end # white: 4294967296 if ( direction = ENV["DIRECTION"].to_u16 ) directions[name] = Math::PI/180*direction else directions[name] = Math::PI/180*rand(360) end obsmediacreate( obs, "meta-bullshit", name, ARGV[0] ) sleep 2 Fiber.yield