Question / Help Timed Scene Change

Nupper

New Member
I am trying to write an autohotkey scene switching macro but having a very difficult time. I am just looking to switch between two scened every 60 seconds. Does anyone know the best way to make something like this work automatically?

Any help would be much appreciated!
 

Suslik V

Active Member
forever loop:
Code:
Loop {
Send, {F3 Down}
 Sleep, 10 ; pause 10ms to allow application to recognize the pressed state
Send, {F3 Up}
Sleep, 60000
Send, {F4 Down}
 Sleep, 10 ; pause 10ms to allow application to recognize the pressed state
Send, {F4 Up}
Sleep, 60000
} Until 0
or something like this, I think.
 
Last edited:

Ohm Audio

New Member
I would pay someone to write me some code for OBS studio, my old one worked fine but won't work with the new platform. I have 12 scenes, any help would be appreciated..
I got this from someone who runs an aquarium channel but it's all gibberish to me, I know it could be edited to suit my needs but I wouldn't know where to start -

https://www.youtube.com/watch?v=kGTagaDMtWk


Code:
; AutoHotKey chat integration and auto-scene switcher for The Cichlid Show

#InstallMouseHook
#InstallKeybdHook
#Persistent
#SingleInstance force
#NoEnv
#UseHook On

#Include c:\seneye\json\AutoHotkey-JSON-master\JSON.ahk

Menu, Tray, Icon, shell32.dll, 110

SetTitleMatchMode, 2
DetectHiddenWindows, On

; global storm API call enabler
storm_enabled := "NO"

scenes_by_name := Object()
scenes_by_name.6 := "QUAD"
scenes_by_name.5 := "FRY"
scenes_by_name.4 := "SIDES"
scenes_by_name.3 := "FRONT"
scenes_by_name.2 := "LEFT"
scenes_by_name.1 := "RIGHT"

; scene ############################

; scene hotkey mappings
QUAD := 6
FRY := 5
SIDES := 4
FRONT := 3
LEFT := 2
RIGHT := 1

DAYTIME := [
, [FRONT,20]
, [FRY,10]
, [RIGHT,15]
, [FRONT,10]
, [LEFT,15] ]

NIGHTTIME := [
, [FRONT,30]
, [RIGHT,30]
, [LEFT,30] ]

STORM := [
, [LEFT,10]
, [FRONT,10]
, [RIGHT,10] ]

slog("mainloop", "starting up")

; YouTube Live Stream Chat API
api_url := <REMOVED>

oplog_messages := ""
message := Object()

; by default we show the oplog
oplog := "true"

; MAINLOOP ####################

Loop {
mode := GetRotationMode()
; GetBlueFishConditions()

; default to auto mode but look for commands every 1 second
For key, value in %mode%
{
GetViewersCount()
WriteOperatorStatus()
result := ProcessChat()
if result.storm
{
mode := GetRotationMode()
slog("debug","storm rotation enabled")
break
}
if result.newProfile
{
mode := GetRotationMode()
slog("debug","new scene requested: " . mode)
break
}
scene := value.1
duration := value.2
RotateAuto(scene, duration, mode)
}
}

; FUNCS ########################

GetBlueFishConditions()
{
; REMOVED
}

slog(log_type,message) {
file := FileOpen("c:\seneye\system_log.txt", "a")
FormatTime, TimeString, R
file.WriteLine(TimeString . " " . log_type . ": " message)
file.Close()
}

SetRotationMode(mode) {
if not mode
{
mode := "DAYTIME"
}
file := FileOpen("c:\seneye\current_mode.cfg", "w")
file.Write(mode)
file.Close()
}

GetRotationMode() {
FileRead, mode, c:\seneye\current_mode.cfg
Return mode
}

ProcessChat() {
global api_url, message, oplog, oplog_messages
user_duration := 60
command := Object()

; download "messages" api via IE com object
WinHttpReq := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WinHttpReq.SetTimeouts("1000", "1000", "1000", "1000")

Try {
WinHttpReq.Open("GET", api_url, false)
WinHttpReq.Send()
WinHttpReq.WaitForResponse()
json_string := WinHttpReq.ResponseText
}
Catch e{
For Each, Line in StrSplit(e.Message, "`n", "") {
Results := InStr(Line, "Description:")
? StrReplace(Line, "Description:")
: ""
If (Results <> "")
Break
}
slog("messages", "youtube live api error")
}

; load JSON YouTube chat data (if any) and parse
parsed_json_string := JSON.Load(json_string)
for index, ele in % parsed_json_string.items
{
id := parsed_json_string.items[index].id
authorChannelId := parsed_json_string.items[index].snippet.authorChannelId
time := parsed_json_string.items[index].snippet.publishedAt
text := parsed_json_string.items[index].snippet.displayMessage

; parse this message only if it's new
If not message[id]
{
slog("messages", "new message found: " . text)
message[id] := id

; if #STORMSTART and #STORMSTOP
IfInString, text, `#STORMSTART
{
command.storm := "START"
slog("messages", "new message found: " . text)
dostorm("start")
}
IfInString, text, `#STORMSTOP
{
command.storm := "STOP"
slog("messages", "new message found: " . text)
dostorm("stop")
}

; if #LOG then show #LOG
IfInString, text, `#SHOWLOG
{
slog("messages", "new message found: " . text)
oplog := "true"
command.toggleoplog := 1
}

; if #HIDELOG then hide #LOG
IfInString, text, `#HIDELOG
{
slog("messages", "new message found: " . text)
oplog := "false"
command.toggleoplog := 1
}

; admin commands
IfInString, authorChannelId, <REMOVED>
{
slog("admin", "new admin command found: " . text)
IfInString, text, `#LOG
{
; remove "#LOG"
StringReplace, text_trimmed, text, `#LOG

; add time to beginning
parsed_time := DateParse(time)
FormatTime, formatted_parsed_time, parsed_time, hh:mm tt' '

oplog_messages = %oplog_messages%%formatted_parsed_time% %text_trimmed%`r`n
slog("admin", "new activity log found " . text_trimmed)
command.newoplog := 1
}
IfInString, text, `#CLEARLOG
{
oplog_messages := ""
slog("admin", "activity log cleared")
command.newoplog := 1
}
IfInString, text, `#DAYTIME
{
slog("messages", "new profile requested " . text)
command.newProfile := "DAYTIME"
SetRotationMode("DAYTIME")
}
IfInString, text, `#NIGHTTIME
{
slog("messages", "new profile requested " . text)
command.newProfile := "NIGHTTIME"
SetRotationMode("NIGHTTIME")
}
}

; write the current log string to disk
WriteOpLog()

; if scene command found in chat then rotate cam to selection
IfInString, text, `#FRONT
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(3,user_duration)
}
IfInString, text, `#LEFT
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(2,user_duration)
}
IfInString, text, `#RIGHT
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(1,user_duration)
}
IfInString, text, `#SIDES
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(4,user_duration)
}
IfInString, text, `#FRY
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(5,user_duration)
}
IfInString, text, `#QUAD
{
slog("messages", "new command found " . text)
command.userScene := 1
RotateUser(6,user_duration)
}
}
}
Return command
}

dostorm(state) {
/* implemented with help from:
* [USER=56035]@author[/USER] Spencer Shepard
* @copyright 2016

<REMOVED>
*/
}

StormTimerEnd(mode) {
SetRotationMode(mode)
slog("storm", "storm ended - switching profile back to " . mode)
Return
}

GetViewersCount() {
; get number of current viewers from YouTube
live_stats := "https://www.youtube.com/live_stats?v=yqqQDRy2zpE"

WinHttpReq := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WinHttpReq.SetTimeouts("1000", "1000", "1000", "1000")

Try {
WinHttpReq.Open("GET", live_stats, true)
WinHttpReq.Send()
WinHttpReq.WaitForResponse()
live_stats_string := WinHttpReq.ResponseText
}
Catch e{
For Each, Line in StrSplit(e.Message, "`n", "") {
Results := InStr(Line, "Description:")
? StrReplace(Line, "Description:")
: ""
If (Results <> "")
Break
}
live_stats_string := "-"
slog("viewerscount", "youtube live api error")
}
file := FileOpen("c:\seneye\youtube_viewers.txt", "w")
file.WriteLine(live_stats_string . " watching")
file.Close()
Return live_stats_string
}

RotateAuto(scene,duration,mode) {
global scenes_by_name, message, oplog
WinActivate OBS
Send "!%scene%"
while duration
{
WriteSceneState(duration,scenes_by_name[scene],mode)
Sleep, 1000
duration := duration - 1
}
Return
}

RotateUser(scene,duration) {
global scenes_by_name, message, oplog
WinActivate OBS
Send "!%scene%"
while duration
{
WriteOpLog()
WriteSceneState(duration,scenes_by_name[scene],"YouTube Live Chat")
Sleep, 1000
duration := duration - 1
}
Return
}

WriteOpLog() {
global oplog_messages, oplog
; write #LOG to disk if #SHOWLOG enabled
If (oplog == "true")
{
if (oplog_messages)
{
file := FileOpen("c:\seneye\operator_messages.txt", "w")
file.WriteLine("(type #HIDELOG in chat to hide this activity feed)")
file.Write(oplog_messages)
file.Close()
}
else
{
file := FileOpen("c:\seneye\operator_messages.txt", "w")
file.WriteLine("no recent activity")
file.Close()
}
}
else
{
; otherwise write an blank file
file := FileOpen("c:\seneye\operator_messages.txt", "w")
file.WriteLine("")
file.Close()
}
}

WriteOperatorStatus() {
; if afk for more than 2 minutes then write a message
if (A_TimeIdlePhysical > 120000)
{
file := FileOpen("c:\seneye\operator_status.txt", "w")
file.WriteLine("admin AFK for " . GetAFKduration(A_TimeIdlePhysical))
file.Close()
}
else
{
file := FileOpen("c:\seneye\operator_status.txt", "w")
file.WriteLine("admin online")
file.Close()
}
}

GetAFKduration(milliseconds) { ; converts milli-seconds to hrs mins and secs
time:=milliseconds/1000
timestring:=ceil((time//3600)) . "h " . ceil((time//60)) . "m"
return timestring
}

WriteSceneState(duration,scene,source) {
file := FileOpen("c:\seneye\scene_state.txt", "w")
; DAYTIME #FRONT (next scene: 12)
file.WriteLine(source . " #" . scene . " (next scene:" . duration . ")")
file.Close()
Return
}

+Space::
Suspend
file := FileOpen("c:\seneye\scene_state.txt", "w")
file.WriteLine("SCENE ROTATION PAUSED")
file.Close()
slog("mainloop", "paused from keyboard")
Pause ,, 1
Return

DateParse(str) {
static e2 = "i)(?:(\d{1,2}+)[\s\.\-\/,]+)?(\d{1,2}|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w*)[\s\.\-\/,]+(\d{2,4})"
str := RegExReplace(str, "((?:" . SubStr(e2, 42, 47) . ")\w*)(\s*)(\d{1,2})\b", "$3$2$1", "", 1)
If RegExMatch(str, "i)^\s*(?:(\d{4})([\s\-:\/])(\d{1,2})\2(\d{1,2}))?"
. "(?:\s*[T\s](\d{1,2})([\s\-:\/])(\d{1,2})(?:\6(\d{1,2})\s*(?:(Z)|(\+|\-)?"
. "(\d{1,2})\6(\d{1,2})(?:\6(\d{1,2}))?)?)?)?\s*$", i)
d3 := i1, d2 := i3, d1 := i4, t1 := i5, t2 := i7, t3 := i8
Else If !RegExMatch(str, "^\W*(\d{1,2}+)(\d{2})\W*$", t)
RegExMatch(str, "i)(\d{1,2})\s*:\s*(\d{1,2})(?:\s*(\d{1,2}))?(?:\s*([ap]m))?", t)
, RegExMatch(str, e2, d)
f = %A_FormatFloat%
SetFormat, Float, 02.0
d := (d3 ? (StrLen(d3) = 2 ? 20 : "") . d3 : A_YYYY)
. ((d2 := d2 + 0 ? d2 : (InStr(e2, SubStr(d2, 1, 3)) - 40) // 4 + 1.0) > 0
? d2 + 0.0 : A_MM) . ((d1 += 0.0) ? d1 : A_DD) . t1
+ (t1 = 12 ? t4 = "am" ? -12.0 : 0.0 : t4 = "am" ? 0.0 : 12.0) . t2 + 0.0 . t3 + 0.0
SetFormat, Float, %f%
Return, d
}
 

Suslik V

Active Member
I would pay someone to write me some code for OBS studio, my old one worked fine but won't work with the new platform. I have 12 scenes, any help would be appreciated..
...
I see your code is complex for casual scripting. Code analysis always cost additional money. If you want to buy cheap code from programmer always ask for a new task. Nobody wants to do double job.

You must set the task. What you want to get, your goal? For example, I have 12 scenes in OBS Studio. I want to switch them randomly, 2...8 sec interval. The switching must be performed after I press special button and ends at the same button press. Switching transition's type on the fly is more complex task. Changing scenes on raising events more complex task, and so on.
 
Top