1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
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
|