Carny_Priest Posted July 28, 2016 Author Share Posted July 28, 2016 The script can be placed anywhere. I keep it in C:\PinballX\Scripts The config file is extracted into the obs-studio root. Then, the path to your profiles would be obs-studio\config\obs-studio\basic\profiles the FP recorder is a mod of gtxjoe's recorder for VP. He packages ffmpeg with his distribution. The default location would be the same folder as where the script is located. In other words ffmpeg.exe would be located in path: script_dir\ffmpeg\bin Open a command prompt, navigate to the obs executable and start a portable instance. obs64 --portable accept the license and you should be good to go. Like everything related to pinball software, I set all executables to start as adminstrator - obs, this compiled script executable, ffmpeg, etc. Snapshots - I don't really use that feature. I can't think why it would not work. If nothing else PinballX has built-in snapshot support, but I guess you'd have to do the renaming of image files. Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 28, 2016 Share Posted July 28, 2016 Ok thanks for the quick reply, i make the necessary adjustments as suggested. The pinball x screenshot feature doesnt work all screenshots are black. Ill report back my results Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted July 28, 2016 Author Share Posted July 28, 2016 Ok, I guess PinballX's screen capture feature does not support OpenGL. Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 29, 2016 Share Posted July 29, 2016 ok its running but the videos are all black, playfiled screenshots are black as well. Videos now recording, but now they are upside down.........un freaking believable Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 29, 2016 Share Posted July 29, 2016 How can you rotate the recorded video 180 degrees? Quote Link to comment Share on other sites More sharing options...
Kustom Kid Posted July 29, 2016 Share Posted July 29, 2016 @rablack97 I've encountered the same issue. See This Thread and try the suggestions there. For what it's worth, for the time being I've just rotated the playfield images to use until the video recording rotation gets sorted out. Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 29, 2016 Share Posted July 29, 2016 16 minutes ago, Kustom Kid said: @rablack97 I've encountered the same issue. See This Thread and try the suggestions there. For what it's worth, for the time being I've just rotated the playfield images to use until the video recording rotation gets sorted out. I fixed it, pretty easy to do, take the source AHK, and look for all instances of "rotation=PI", and replace with "rotation=0". Rotation=PI is the radian command for 180 degrees. I'm gonna write up an install tutorial, i have it working fully automated. Video's, and still images are being created and foldered properly now. 1 Quote Link to comment Share on other sites More sharing options...
Kustom Kid Posted July 29, 2016 Share Posted July 29, 2016 It's still no worky for me. I'm running in desktop mode which isn't officially supported at the moment. Happy to hear you have it sorted out though! Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted July 29, 2016 Author Share Posted July 29, 2016 9 hours ago, rablack97 said: I fixed it, pretty easy to do, take the source AHK, and look for all instances of "rotation=PI", and replace with "rotation=0". Rotation=PI is the radian command for 180 degrees. I'm gonna write up an install tutorial, i have it working fully automated. Video's, and still images are being created and foldered properly now. I'm glad that you got it working for yourself. Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 29, 2016 Share Posted July 29, 2016 One issue i did find is the output for the obs is hard set to pinballx/scripts, placing the ffmpeg and the script in that folder got the video and automation working without a hitch Quote Link to comment Share on other sites More sharing options...
rablack97 Posted July 30, 2016 Share Posted July 30, 2016 Hello, I had a hell of a time configuring this awesome program for Future Pinball, so i modified Carny_Priests post to help others that may want to use it. Future Pinball, Win10 64bit Hi, the latest OBS studio added command line support for multiple profiles, so I ported gtxjoe's version 1.4 to support capturing Future Pinball tables. It has all the features of 1.4 except that it supports only Future Pinball and uses OBS Studio as the capture engline for playfield, backglass, DMD. Ffmpeg is still required to complete the transcode to generate the final output. Latest OBS Studio for Windows (portable zip): https://github.com/jp9000/obs-studio/releases/download/0.14.1/OBS-Studio-0.14.1.zip Rename folder "obs-studio" and place here. Download https://www.gameex.info/forums/applications/core/interface/file/attachment.php?id=27458 Place file here Open a command prompt and navigate to obs-studio\bin\64bit execute obs64 --portable Agree to the license. The next screen should look something like this. If the profile and scenes are not defaulted to 'playfield', click on profile and scene collection and select 'playfield'. There are pre-existing profiles, scene collections, and sources for playfield, bg, and dmd. Each source captures an entire screen. You may want to confirm that each profile is capturing the correct screen. Click the settings icon for display capture in each profile and see that the preview is displaying the correct screen. You can change the screen using the pull down menu. Check playfield and then repeat for bg or backglass. The script assumes that full screens are used for playfield and bg. Ffmpeg will automatically crop the DMD video based on your FutureDMD settings. Make sure your video output is set as shown below. Make sure your video setting are set as appropriate, in my case 1920X1080 worked perfect. Download FFMPEG from here - latest version, rename the folder FFMPEG https://ffmpeg.zeranoe.com/builds/win64/static/ Download The 64bit script executable is here: https://dl.dropboxusercontent.com/u/45430846/PBXrecorder_x64_1.4FP.exe Create a folder in your PinballX folder, name is 'Scripts', place the PBXrecorder_x64_1.4FP.exe and FFMPEG folder inside of this folder Right click on the script, choose compatibility tab, check "Run this program as administrator" Do the same for FFMPEG And OBS64 Create a shortcut to the script and place on your desktop and your good to go. If your tables are rotated and upside down, attached is the script that will turn them the correct way. Hope this helps. PBXrecorder_x64_1.4FP_180.exe Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted September 18, 2016 Author Share Posted September 18, 2016 On 5/12/2016 at 10:01 PM, Carny_Priest said: Hi, I installed Unit3D Pinball last year, but I just now finally got around to coding a launcher for myself. The timing is pretty good as it seems the French Pinball Team is pretty close to releasing Roadshow. In any case, I need media so I ported gtxjoe's PBX Recorder to capture Unit3D. Works pretty much the same way as PBX Recorder. It uses ffmpeg as the capture engine. The 64bit compiled executable is here: https://dl.dropboxusercontent.com/u/45430846/PBXrecorder_1.4Unit3D.exe As always, run as admin. This can co-exist in the same folder as PBXRecorder for VP. The log will get overwritten but it creates an ini file with a different file name. Output will look best and work trouble free with the LAV filters that are linked on the PinballX home page. Unit3D only supports two screens by spanning the game window over to the backglass display while running cab calibration. DMD settings are still part of the ini, but any selections will be ignored. The script assumes that "Unit3D" is contained in the name assigned to your Unit3D system (e.g., the databases have file names such as "Unit3D.xml" or "Unit3D Pinball.xml"). The script assumes that your displays will be set up in a standard fashion with playfield screen in landscape orientation and backglass to the right in landscape orientation. The tops of the screens aligned on the same axis. If you do have Unit3D setup with the playfield screen in portrait orientation then you will probably need to make a minor tweak to the script so that the output will be saved in the correct orientation for display in PinballX. Capture settings are read from Config\CabCalibration.xml. No sense trying to capture anything until you are sure the tables are playing correctly. Script still checks for missing wheels and will direct to Visual Pinball\Wheel Images on the FTP if you enter in your account information. Source: Reveal hidden contents ;PBX recorder 1.4Unit3D (May 12, 2016) LoadTime:= 15 ;How long to allow table to load/start (in sec) ;*****Start log file FileDelete %A_ScriptDir%\PBXrecorder.log FileAppend, %A_MMMM% %A_DD%`,%A_YYYY% %A_Hour%:%A_Min%:%A_Sec%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, Version 1.4Unit3D`n, %A_ScriptDir%\PBXrecorder.log ;*******If table drag and drop use, record only that table ************************* Loop %0% { GivenPath := %A_Index% Loop %GivenPath%, 1 { DragAndDropFile = %A_LoopFileLongPath% } SplitPath, DragAndDropFile, DragAndDropFileName, DragAndDropFileDir, DragAndDropFileExtOnly, DragAndDropFileNameOnly If ((InStr(DragAndDropFileExtOnly, "upt")) = 1) DragAndDrop := 1 ; Else If ((InStr(DragAndDropFileExtOnly, "vpx")) = 1) ; DragAndDrop := 1 Else { Msgbox Error: %DragAndDropFileName% is not a Unit3D table ExitApp } FileAppend, Drag and Drop used: %DragAndDropFile%`n, %A_ScriptDir%\PBXrecorder.log DragText = --------------------------- Drag and drop mode ---------------------------`n%DragAndDropFileName%`n------------------------------------------------------------------------------ Break } ;***************Monitor setup details SysGet, MonitorCount, MonitorCount SysGet, MonitorPrimary, MonitorPrimary FileAppend, `nMonitor Count: %MonitorCount%`, Primary Monitor: %MonitorPrimary%`n, %A_ScriptDir%\PBXrecorder.log Loop, %MonitorCount% { SysGet, MonitorName, MonitorName, %A_Index% SysGet, Monitor, Monitor, %A_Index% SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index% ;MsgBox, Monitor %A_Index%: %MonitorRight%x%MonitorBottom% (%MonitorName%) FileAppend, Monitor %A_Index%: %MonitorRight%x%MonitorBottom% (%MonitorName%)`n, %A_ScriptDir%\PBXrecorder.log } ;************************************************************************************************ ;************************************************************************************************ ;Create/Load PinballX recorder settings ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ Version:=4 NumOfSettings:=12 LoadTimeX:=LoadTime*10 PBXRPauseMode:=0 BetaMode:=0 ;0=Normal mode, 1=Beta mode will store recorded media in a Beta folder ;Load PBXrecorder settings if they exist IfExist, %A_ScriptDir%\PBXrecorderUnit3D.ini { ;Load Existing settings from file ;************************* Loopcount:=0 Loop, Read, %A_ScriptDir%\PBXrecorderUnit3D.ini { If (Loopcount = 0) VersionRead:= A_LoopReadLine Else If (Loopcount=1) PinballXPath := A_LoopReadLine Else If (Loopcount=2) OnlyRecordMissingVideos := A_LoopReadLine Else If (Loopcount=3) PFVideoOnly := A_LoopReadLine Else If (Loopcount=4) BGVideoOnly := A_LoopReadLine Else If (Loopcount=5) DMDVideoOnly := A_LoopReadLine Else If (Loopcount=6) PFImageOnly := A_LoopReadLine Else If (Loopcount=7) BGImageOnly := A_LoopReadLine Else If (Loopcount=8) DMDImageOnly := A_LoopReadLine Else If (Loopcount=9) RecFormat := A_LoopReadLine Else If (Loopcount=10) RecTime := A_LoopReadLine Else If (Loopcount=11) MediaFileNaming := A_LoopReadLine Loopcount:=Loopcount + 1 } ;Check Version of ini file ;************************* If ((Version=VersionRead) and (LoopCount=NumOfSettings)) ;If ini version matches, process, else force user to update settings { ;Display ini settings ;************************* If (OnlyRecordMissingVideos = 2) TempStr2 := "`nFind and record missing media files only`n(Existing media files are kept)" Else If (OnlyRecordMissingVideos = 1) TempStr2 := "`nRecord complete media set for new and incomplete tables`n(Incomplete media sets are deleted/re-recorded)" Else If (OnlyRecordMissingVideos = 3) TempStr2 := "`nRecord complete media set for new tables only`n(If any media is found, the table is skipped. Tables with no media are recorded)" Else TempStr2 := "`nStart over and record complete media sets for all tables`n(All existing media is replaced)" If RecFormat = 1 RecExt=mp4 Else RecExt=f4v TempStr1 = `nMedia to Record (%RecTime% sec %RecExt% videos):`n If (PFVideoOnly=1) TempStr1 = %TempStr1%Playfield Videos`n If (BGVideoOnly=1) TempStr1 = %TempStr1%Backglass Videos`n If (DMDVideoOnly=1) TempStr1 = %TempStr1%DMD Videos`n If (PFImageOnly=1) TempStr1 = %TempStr1%Playfield Images`n If (BGImageOnly=1) TempStr1 = %TempStr1%Backglass Images`n If (DMDImageOnly=1) TempStr1 = %TempStr1%DMD Images`n If (MediaFileNaming=0) TempStr1 = %TempStr1%`nMedia filename based on Description tags`n Else TempStr1 = %TempStr1%`nMedia filename based on Unit3D table filename`n If (DragAndDrop<>1) ; if drag and drop not used, display settings { ;Prompt user if change to settings desired ;************************* SetTimer, CurrSettingsButtonNames, 50 Msgbox, 4, Current Recorder Settings, %DragText%`n`nPinballX Path: %PinballXPath%`n%TempStr2%`n%TempStr1%`n`n`nPress ESC to abort script IfMsgBox, NO Change := 1 } } Else { Msgbox, New version of the video recorder detected. Please update settings Change := 1 } } Else ;No PBXRecorderUnit3D.ini found. Need to Create the ini file { ;******* PBXR settings needed ****************** Change := 1 PinballXPath = C:\PinballX } ;*****Create Pinballx.net FTP login file if not exist IfNotExist, %A_ScriptDir%\FTPLoginInfo.txt { FileAppend, **** To enabled Wheel Image downloads - Replace USERNAME and PASSWORD with your Pinballx FTP login info (requires subscription)`n, %A_ScriptDir%\FTPLoginInfo.txt FileAppend, USERNAME`n, %A_ScriptDir%\FTPLoginInfo.txt FileAppend, PASSWORD`n, %A_ScriptDir%\FTPLoginInfo.txt } ; User needs to update PBX Recorder ini settings ;************************* If (Change = 1) { ;Pinballx folder Msgbox, 4,PBXrecorder Settings, PinballX folder: %PinballXPath%`n`n Do you want to change the Pinballx path? `n IfMsgBox Yes ;display folder selection dialog { FileSelectFolder, PinballXPath,,0,Select the Pinballx Folder PinballXPath := RegExReplace(PinballXPath, "\\$") } ;Pic Record Mode Gui, Show, W810 H170, Record Mode gui, font, s10, Arial Gui, Add, Radio, checked vMRadioGroup1, Find and record missing media files only (Existing media files are kept. No files deleted) Gui, Add, Radio, vMRadioGroup4, Record complete media set for new tables only (If any media is found, the table is skipped. Only tables with no media are recorded) Gui, Add, Radio, vMRadioGroup2, Record complete media set for new and incomplete tables (Missing media is recorded. Incomplete media sets are deleted/re-recorded) Gui, Add, Radio, vMRadioGroup3, Start over and record complete media sets for all tables (All existing media is deleted and re-recorded) Gui, Add, Text,, `n Gui, Add, Button, Default gMediaMode, Next Gui, Show WinWaitClose, Record Mode ;Choose what media to record Gui, Show, W400 H280, Choose Media to Record gui, font, s10, Arial Gui, Add, Text,,Videos Gui, Add, Checkbox, vPFVid, Playfield Videos Gui, Add, Checkbox, vBGVid, Backglass Videos Gui, Add, Checkbox, vDMDVid, DMD Videos (Req 3 Monitor setup) Gui, Add, Text,,`nImages Gui, Add, Checkbox, vPFImage, Playfield Image Gui, Add, Checkbox, vBGImage, Backglass Image Gui, Add, Checkbox, vDMDImage, DMD Image (Req 3 Monitor setup) Gui, Add, Text,, `n Gui, Add, Button, Default gConfirm, Next Gui, Show WinWaitClose, Choose Media to Record ;Set the video recording time Gui, Show, W400 H260, Video Recording Time gui, font, s10, Arial Gui, Add, Text,,Select duration of video recordings:`n Gui, Add, Radio, vRadioGroup1, 5 seconds Gui, Add, Radio, vRadioGroup2, 15 seconds Gui, Add, Radio, vRadioGroup3, 30 seconds Gui, Add, Radio, Checked vRadioGroup4, 60 seconds Gui, Add, Radio, vRadioGroup5, 120 seconds Gui, Add, Radio, vRadioGroup6, 300 seconds Gui, Add, Text,, `n Gui, Add, Button, Default gSelect, Next Gui, Show WinWaitClose, Video Recording Time ;Recording Format Gui, Show, W500 H170, Recording Format gui, font, s10, Arial Gui, Add, Text,,Record all videos in:`n Gui, Add, Radio, checked vRadioGroupRF1, .f4v format Gui, Add, Radio, vRadioGroupRF2, .mp4 format Gui, Add, Text,, `n Gui, Add, Button, Default gMediaR, Next Gui, Show WinWaitClose, Recording Format ;File naming convention Gui, Show, W500 H170, Media Naming gui, font, s10, Arial Gui, Add, Text,,Media filenames should be based on:`n Gui, Add, Radio, checked vRadioGroupMF1, Description tag Example: Dr. Dude (Bally 1990).%RecExt% Gui, Add, Radio, vRadioGroupMF2, Unit3D table filename Example: Dr Dude.%RecExt% Gui, Add, Text,, `n Gui, Add, Button, Default gMediaF, Next Gui, Show WinWaitClose, Media Naming ;******Save Settings***** FileDelete %A_ScriptDir%\PBXrecorderUnit3D.ini FileAppend,%Version%`n%PinballXPath%`n%OnlyRecordMissingVideos%`n%PFVideoOnly%`n%BGVideoOnly%`n%DMDVideoOnly%`n%PFImageOnly%`n%BGImageOnly%`n%DMDImageOnly%`n%RecFormat%`n%RecTime%`n%MediaFileNaming%`n, %A_ScriptDir%\PBXrecorderUnit3D.ini ;Display ini settings If (OnlyRecordMissingVideos = 2) TempStr2 := "`nFind and record missing media files only`n(Existing media files are kept)" Else If (OnlyRecordMissingVideos = 1) TempStr2 := "`nRecord complete media set for new and incomplete tables`n(Incomplete media sets are deleted/re-recorded)" Else If (OnlyRecordMissingVideos = 3) TempStr2 := "`nRecord complete media set for new tables only`n(If any media is found, the table is skipped. Tables with no media are recorded)" Else TempStr2 := "`nStart over and record complete media sets for all tables`n(All existing media is replaced)" If RecordingFormat = 1 RecExt=mp4 Else RecExt=f4v TempStr1 = `nMedia to Record (%RecTime% sec %RecExt% videos):`n If (PFVideoOnly=1) TempStr1 = %TempStr1%Playfield Videos`n If (BGVideoOnly=1) TempStr1 = %TempStr1%Backglass Videos`n If (DMDVideoOnly=1) TempStr1 = %TempStr1%DMD Videos`n If (PFImageOnly=1) TempStr1 = %TempStr1%Playfield Images`n If (BGImageOnly=1) TempStr1 = %TempStr1%Backglass Images`n If (DMDImageOnly=1) TempStr1 = %TempStr1%DMD Images`n If (MediaFileNaming=0) TempStr1 = %TempStr1%`nMedia filename based on Description tags`n Else TempStr1 = %TempStr1%`nMedia filename based on VP table filename`n Msgbox, 0, Current Recorder Settings, PinballX Path: %PinballXPath%`n%TempStr2%`n%TempStr1%`n(Wheel Image download support. See FTPLoginInfo.txt)`n`n`nPress ESC to abort script } FileAppend,`nPinballx.ini`n%Version%`n%PinballXPath%`n%OnlyRecordMissingVideos%`n%PFVideoOnly%`n%BGVideoOnly%`n%DMDVideoOnly%`n%PFImageOnly%`n%BGImageOnly%`n%DMDImageOnly%`n%RecFormat%`n%RecTime%`n%MediaFileNaming%`n`nIdentify all Unit3D XML files...`n, %A_ScriptDir%\PBXrecorder.log ;Set FFMpeg and MediaOut folder locations FFMpegPath = %A_ScriptDir%\FFMpeg\bin MediaOutPath = %PinballXPath%\Media ;************************************************************************************************ ;************************************************************************************************ ;2. Time to walk find all the Unit3D xml files ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ;Arrays for finding and storing Unit3D xml files and path information XMLPathArray := Object() XMLFileNameArray := Object() WorkingPathArray := Object() TablePathArray := Object() ExecutableArray := Object() ;Array[j] := A_LoopField ; Array of xml search strings Array := ["[VisualPinball]", "Enabled=", "WorkingPath=", "TablePath=", "Executable=", "[System_", "Name=", "WorkingPath=", "TablePath=", "Executable=", "Enabled=", "SystemType=", "XXXX END XXXX"] ; 1 2 3 4 5 6 7 8 9 10 11 12 13 VPXMLCount=1 VPSearchIndex:=1 VPActiveFlag=0 VPKeepFlag = 1 ;Assume System is enabled VPSystemFlag = 0 VPFirstSystemDone = 0 If (DragAndDrop<>1) PauseTime:=200 Else PauseTime:=0 ;Open PinballX.ini file and identify Unit3D xml files ;================================================= Loop, Read, %PinballXPath%\Config\PinballX.ini { ;****** Find 1st System ****** If (VPFirstSystemDone=0 and VPActiveFlag=0) ;Search for 1st System start { StringGetPos, Position, A_LoopReadLine, [VisualPinball] If Position = 0 { VPActiveFlag = 1 TempStr = %PinballXPath%\Databases\Visual Pinball XMLPathArray[VPXMLCount] := TempStr XMLFileNameArray[VPXMLCount] := "Visual Pinball" TempStr1 := XMLPathArray[VPXMLCount] TempStr2 := XMLFileNameArray[VPXMLCount] ;Msgbox, XMLPathArray[%VPXMLCount%]=%TempStr1%\%TempStr2% } else { continue ;Read next line } } else if (VPFirstSystemDone==0 and VPActiveFlag==1) ;Collect info for 1st system { StringGetPos, Position, A_LoopReadLine, WorkingPath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 13) WorkingPathArray[VPXMLCount] := TempStr1 TempStr2 := WorkingPathArray[VPXMLCount] ;Msgbox WorkingPathArray[%VPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Tablepath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 11) TablePathArray[VPXMLCount] := TempStr1 TempStr2 := TablePathArray[VPXMLCount] ;Msgbox TablePathArray[%VPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Executable If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 12) ExecutableArray[VPXMLCount] := TempStr1 TempStr2 := ExecutableArray[VPXMLCount] ;Msgbox ExecutableArray[%VPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Enabled=True If Position = 0 { VPKeepFlag = 1 ;MsgBox, enabled is true } StringGetPos, Position, A_LoopReadLine, Enabled=False If Position = 0 { VPKeepFlag = 0 ;MsgBox, enabled is false } StringGetPos, Position, A_LoopReadLine, [ ;End of section found If Position = 0 { VPFirstSystemDone=1 StringGetPos, pos, A_LoopReadLine, [ if pos = 0 { If VPKeepFlag = 1 ;Keep System info { TempStr1 := XMLPathArray[VPXMLCount] TempStr2 := XMLFileNameArray[VPXMLCount] TempStr3 := WorkingPathArray[VPXMLCount] TempStr4 := TablePathArray[VPXMLCount] TempStr5 := ExecutableArray[VPXMLCount] ;Msgbox, XMLPathArray[%VPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%VPXMLCount%]=%TempStr3%`n TablePathArray[%VPXMLCount%]=%TempStr4%`n ExecutableArray[%VPXMLCount%]=%TempStr5% ; FileAppend, VP System #%VPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log ; VPXMLCount++ } Else { ; FileAppend, `nVisual Pinball System is disabled in the XML file`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%VPSystemFlag% %VPKeepFlag%) } VPActiveFlag = 0 VPKeepFlag = 1 ;Assume System is enabled } ; Need to check this line if it is the start of a new system StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { VPActiveFlag = 1 } } } ;****** Find Extra Systems ****** Else If (VPFirstSystemDone=1 and VPActiveFlag = 0) ;Search for start extra [System...] sections { StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { VPActiveFlag = 1 } else { continue ;Read next line } } else if (VPFirstSystemDone=1 and VPActiveFlag = 1) ;Collect info for the additional [System... sections { StringGetPos, Position, A_LoopReadLine, Name If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 6) TempStr = %PinballXPath%\Databases\%TempStr1% XMLPathArray[VPXMLCount] := TempStr XMLFileNameArray[VPXMLCount] := TempStr1 ;Msgbox, XMLPathArray[%VPXMLCount%]=%TempStr%\%TempStr1% } StringGetPos, Position, A_LoopReadLine, WorkingPath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 13) WorkingPathArray[VPXMLCount] := TempStr1 TempStr2 := WorkingPathArray[VPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, Tablepath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 11) TablePathArray[VPXMLCount] := TempStr1 TempStr2 := TablePathArray[VPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, Executable If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 12) ExecutableArray[VPXMLCount] := TempStr1 TempStr2 := ExecutableArray[VPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, SystemType=0 If Position = 0 { VPSystemFlag = 1 ;MsgBox, System is Custom } StringGetPos, Position, A_LoopReadLine, Enabled=True If Position = 0 { VPKeepFlag = 1 ;MsgBox, System Enabled } StringGetPos, Position, A_LoopReadLine, Enabled=False If Position = 0 { VPKeepFlag = 0 ;MsgBox, System Disabled } StringGetPos, Position, A_LoopReadLine, [ If Position = 0 { TempStr := XMLFileNameArray[VPXMLCount] StringGetPos, Position, TempStr, Unit3D ;Name contains Unit3D If (VPSystemFlag = 1 and VPKeepFlag = 1 and Position >= 0) ;Keep System info { TempStr1 := XMLPathArray[VPXMLCount] TempStr2 := XMLFileNameArray[VPXMLCount] TempStr3 := WorkingPathArray[VPXMLCount] TempStr4 := TablePathArray[VPXMLCount] TempStr5 := ExecutableArray[VPXMLCount] ;Msgbox, XMLPathArray[%VPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%VPXMLCount%]=%TempStr3%`n TablePathArray[%VPXMLCount%]=%TempStr4%`n ExecutableArray[%VPXMLCount%]=%TempStr5% FileAppend, Unit3D System #%VPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log VPXMLCount++ } Else { TempStr2 := XMLFileNameArray[VPXMLCount] FileAppend, Skipping this system: %TempStr2%.xml`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%VPSystemFlag% %VPKeepFlag%) } VPActiveFlag = 0 VPKeepFlag = 1 ;Assume System is enabled VPSystemFlag = 0 ; Need to check this line if it is the start of a new system StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { VPActiveFlag = 1 } } } } ;End of file found, process last system found TempStr := XMLFileNameArray[VPXMLCount] StringGetPos, Position, TempStr, Unit3D ;Name contains Unit3D If (VPSystemFlag = 1 and VPKeepFlag = 1 and Position >= 0) ;Keep System info { TempStr1 := XMLPathArray[VPXMLCount] TempStr2 := XMLFileNameArray[VPXMLCount] TempStr3 := WorkingPathArray[VPXMLCount] TempStr4 := TablePathArray[VPXMLCount] TempStr5 := ExecutableArray[VPXMLCount] ;Msgbox, XMLPathArray[%VPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%VPXMLCount%]=%TempStr3%`n TablePathArray[%VPXMLCount%]=%TempStr4%`n ExecutableArray[%VPXMLCount%]=%TempStr5% FileAppend, VP System #%VPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log VPXMLCount++ } Else { TempStr2 := XMLFileNameArray[VPXMLCount] FileAppend, Skipping this system: %TempStr2%.xml`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%VPSystemFlag% %VPKeepFlag%) } VPActiveFlag = 0 VPKeepFlag = 0 VPSystemFlag = 0 VPXMLCount-- FileAppend, Total number of Unit3D systems found: %VPXMLCount%`n, %A_ScriptDir%\PBXrecorder.log If VPXMLCount = 0 { Msgbox No XML files were found. Check PinballX path. } ;************************************************************************************************ ;************************************************************************************************ ;3. If table selected via drag drop or right click, Allow user to add table to XML file ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ If (DragAndDrop=1) { Loop, %VPXMLCount% ;Search if table exists in XML files already { XMLPath:=XMLPathArray[A_Index] XMLFileName:=XMLFileNameArray[A_Index] WorkingPath:=WorkingPathArray[A_Index] TablePath:=TablePathArray[A_Index] Executable:=ExecutableArray[A_Index] FileAppend, `nAdding table to %XMLFileName%.xml (%A_Hour%:%A_Min%:%A_Sec%)`n`n, %A_ScriptDir%\PBXrecorder.log ;Open XML file and walk through every table ;========================== Loop, Read, %XMLPath%\%XMLFilename%.xml { IfInString, A_LoopReadLine, game name= { TableEnabled := 1 StringGetPos, start, A_LoopReadLine, = StringGetPos, end, A_LoopReadLine, > XTable := SubStr(A_LoopReadLine, start+3, end-start-3) ;----------------------------------------------------- ;Convert special chars in Table Name so they are used correctly ;----------------------------------------------------- ;Special handling for & in the Table Name. Change & to & IfInString, XTable, & { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+6) XTable = %TestTable%&%TestTable2% } ;Special handling for italian ' in the Table Name. Change ’ to ' IfInString, XTable, ’ { StringGetPos, start, XTable, ’ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+4) XTable = %TestTable%'%TestTable2% } ;Special handling for ™ in the Table Name. Change ™ to ™ IfInString, XTable, ™ { StringGetPos, start, XTable, ™ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+8) XTable = %TestTable%™%TestTable2% } If inStr(XTable, DragAndDropFileNameOnly) { XMLTableFound := 1 ;Table found in XML files, go ahead and record media break } } ;End of Else IfInString, A_LoopReadLine, /game } ;End of Loop, Read, %XMLPath%\%XMLFilename%.xml If (XMLTableFound=1) ;Table was found in XML files, go ahead and record media { break ;exit loop to record media } } ;End of Loop, %VPXMLCount% If (XMLTableFound<>1) ; XML table not found, so display XML dialog to add table to XML file { IPDBArray := Object() IPDBNameArray := Object() IPDBMfrArray := Object() IPDBYearArray := Object() IPDBTypeArray := Object() IPDBStart:=0 XMLAllStart:=0 XMLMatchFound:=0 Loop, %VPXMLCount% ;Create XML system list for the dialog { theXMLString2:=XMLPathArray[A_Index] SplitPath, theXMLString2,,,, theXMLString If (XMLAllStart = 0) ;Creating XML system list { XMLAllVPSysString=%theXMLString%| XMLAllStart := 1 } Else { XMLAllVPSysString = %XMLAllVPSysString%%theXMLString%| } ;Check if table path matches the current Unit3D system path, if so mark xml system as default by adding extra | If (XMLMatchFound=0) { xmltpath:=TablePathArray[A_Index] If (xmltpath = DragAndDropFileDir) { XMLMatchFound:=1 XMLAllVPSysString = %XMLAllVPSysString%| ;also store executable for launch button LaunchExecutable:=ExecutableArray[A_Index] ;msgbox match%xmltpath% : %DragAndDropFileDir% } } } IfNotExist, %A_ScriptDir%\ipdb list.txt Msgbox, Please re-download PBX Recorder - ipdb list.txt file is missing Loop, Read, %A_ScriptDir%\ipdb list.txt ; Create the ipdb pinball table list for the dialog { StringSplit, TempWordArray, A_LoopReadLine,|, IPDBNameArray.Insert(TempWordArray1) ; Append this line to the array. IPDBMfrArray.Insert(TempWordArray4) ; Append this line to the array. IPDBYearArray.Insert(TempWordArray7) ; Append this line to the array. IPDBtypeArray.Insert(TempWordArray10) ; Append this line to the array. tempIPDB = %TempWordArray1% (%TempWordArray4% %TempWordArray7%) IPDBArray.Insert(tempIPDB) ; Append this line to the array. If (IPDBStart = 0) { allIPDBString = %tempIPDB% IPDBStart := 1 } Else allIPDBString = %allIPDBString%|%tempIPDB% } ; File drag and drop - store filename Loop %0% { GivenPath := %A_Index% Loop %GivenPath%, 1 DragAndDropFile = %A_LoopFileLongPath% DragAndDrop := 1 Break } SplitPath, DragAndDropFile,,,, DragAndDropFileNameOnly ;****** Display the XML Table entry dialog bpx ****** Gui, Font, S11 CDefault, Verdana Gui, Add, Text, x42 y22 w90 h20 +right , XML List Gui, Add, Text, x42 y52 w90 h20 +right, Game Gui, Add, Text, x42 y80 w90 h20 +right, Description Gui, Add, DropDownList, x142 y20 w280 h25 r10 altSubmit vXMLVPSystem, %XMLAllVPSysString% Gui, Add, Button, x442 y18 w100 h29 gXMLLaunch , Launch Gui, Add, Edit, x142 y50 w400 h25 vXMLTableFileName , %DragAndDropFileNameOnly% Gui, Add, Edit, x142 y80 w400 h20 vXMLDescText, Gui, Add, DropDownList, x146 y102 w396 h80 r10 sort altSubmit vXMLDescSelected gGetXMLDescSelected, %allIPDBString% ; IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, DB2S Found ; Else IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.exe ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, B2S.exe Found ; Else ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, DB2S Rename Gui, Add, Text, x142 y130 w220 h20 +center , Manufacturer Gui, Add, Text, x372 y130 w80 h20 +center , Year Gui, Add, Text, x462 y130 w80 h20 +center , Type Gui, Add, Edit, x142 y150 w220 h25 vXMLMfr, Gui, Add, Edit, x372 y150 w80 h25 vXMLYear, Gui, Add, Edit, x462 y150 w80 h25 vXMLType, Gui, Add, CheckBox, x142 y180 w120 h30 Checked vXMLEnabled, Table Enabled Gui, Add, CheckBox, x302 y180 w100 h30 Checked vXMLHideDMD, Hide DMD Gui, Add, CheckBox, x412 y180 w150 h30 Checked vXMLHideBG, Hide Backglass ; Gui, Add, DropDownList, x142 y215 w120 h25 r10 +center altSubmit vXMLAltExe, No Exe Tag||AlternateExe| Exe ; Gui, Add, Edit, x262 y216 w170 h25 vXMLAltExeName, Gui, Add, DropDownList, x442 y215 w100 h25 r10 +center altSubmit vXMLRating, No Rating||1 out of 5|2 out of 5|3 out of 5|4 out of 5|5 out of 5 Gui, Add, Button, x22 y280 w140 h30 gXMLCancel, Cancel Gui, Add, Button, x212 y280 w140 h30 gXMLSaveExit, Save && Exit Gui, Add, Button, x402 y280 w140 h30 gXMLSave, Save && Record GuiControl, Focus, XMLDescSelected Gui, Show, x127 y87 h327 w574,Add Table to XML - Start typing to perform Description auto-complete WinWaitClose, Add Table to XML - Start typing to perform Description auto-complete ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx } Else { MsgBox, 4,, Table exists in XML file already. Begin recording? (press Yes or No) IfMsgBox No ExitApp } } ;************************************************************************************************ ;************************************************************************************************ ;4. Time to walk through the tables and record videos ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ; Disabling "Application has stopped Working" dialog ;(https://www.raymond.cc/blog/disable-program-has-stopped-working-error-dialog-in-windows-server-2008/) RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\Windows Error Reporting, DontShowUI, 0x00000001 Rectime := Rectime + 5 ;Pad record time by 5 seconds Loopcount:=0 Recordcount:=0 Loop, %VPXMLCount% { XMLPath:=XMLPathArray[A_Index] XMLFileName:=XMLFileNameArray[A_Index] WorkingPath:=WorkingPathArray[A_Index] TablePath:=TablePathArray[A_Index] Executable:=ExecutableArray[A_Index] Position := InStr(TablePath,"\TABLES", false) - 1 StringLeft, XTablePath, TablePath, Position FileAppend, `nWorking on %XMLFileName%.xml (%A_Hour%:%A_Min%:%A_Sec%)`n`n, %A_ScriptDir%\PBXrecorder.log ;Save CabCalibration.xml to PBX recorder log FileAppend, CabCalibration.xml`n, %A_ScriptDir%\PBXrecorder.log IfNotExist, %XTablePath%\Config\CabCalibration.xml FileAppend, WARNING: CabCalibration.xml is missing. Will default Playfield size to 1920x1080`n, %A_ScriptDir%\PBXrecorder.log Loop, Read, %XTablePath%\Config\CabCalibration.xml, %A_ScriptDir%\PBXrecorder.log { FileAppend, %A_LoopReadLine%`n } ;FFMPEG file check IfNotExist, %FFMpegPath%\ffmpeg.exe { FFMpegPath = %FFMpegPath%\bin IfNotExist, %FFMpegPath%\ffmpeg.exe FileAppend, `nWARNING: The file ffmpeg.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file ffmpeg.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file ffmpeg.exe could not be found`n`n, %A_ScriptDir%\PBXrecorder.log } ;Open CabCalibration.XML file - may need to be even number values or it may not record ;========================== IfExist, %XTablePath%\Config\CabCalibration.xml { Loop, Read, %XTablePath%\Config\CabCalibration.xml { IfInString, A_LoopReadLine, name="Cabinet" Screen := 1 IfInString, A_LoopReadLine, name="TRANSLITE" Screen := 2 IfInString, A_LoopReadLine, <topleft> Coord := 1 IfInString, A_LoopReadLine, <bottomright> Coord := 2 IfInString, A_LoopReadLine, <screenpos> { If (Screen=1 AND Coord=1) { StringGetPos, start, A_LoopReadLine, > StringGetPos, end, A_LoopReadLine, `, PFTLx := SubStr(A_LoopReadLine, start+2, end-start-1) StringGetPos, start, A_LoopReadLine, `, StringGetPos, end, A_LoopReadLine, <, L2 PFTLy := SubStr(A_LoopReadLine, start+2, end-start-1) } If (Screen=1 AND Coord=2) { StringGetPos, start, A_LoopReadLine, > StringGetPos, end, A_LoopReadLine, `, PFBRx := SubStr(A_LoopReadLine, start+2, end-start-1) StringGetPos, start, A_LoopReadLine, `, StringGetPos, end, A_LoopReadLine, <, L2 PFBRy := SubStr(A_LoopReadLine, start+2, end-start-1) } If (Screen=2 AND Coord=1) { StringGetPos, start, A_LoopReadLine, > StringGetPos, end, A_LoopReadLine, `, BGTLx := SubStr(A_LoopReadLine, start+2, end-start-1) StringGetPos, start, A_LoopReadLine, `, StringGetPos, end, A_LoopReadLine, <, L2 BGTLy := SubStr(A_LoopReadLine, start+2, end-start-1) } If (Screen=2 AND Coord=2) { StringGetPos, start, A_LoopReadLine, > StringGetPos, end, A_LoopReadLine, `, BGBRx := SubStr(A_LoopReadLine, start+2, end-start-1) StringGetPos, start, A_LoopReadLine, `, StringGetPos, end, A_LoopReadLine, <, L2 BGBRy := SubStr(A_LoopReadLine, start+2, end-start-1) } } ;End of Else IfInString, A_LoopReadLine, /CabCalibration } ;End of Loop, Read, %XTablePath%\Config\CabCalibration.xml PF_Width:=PFBRx-PFTLx PF_Height:=PFTLy-PFBRy BG_Width:=BGBRx-BGTLx BG_Height:=BGBRy-BGTLy } IfNotExist, %XTablePath%\Config\CabCalibration.xml { PF_Width:=1920 PF_Height:=1080 } ;Create Media directories if needed ;========================== MediaSubDir:=XMLFileName MediaSubDirOut:=XMLFileName If (BetaMode=1) { MediaSubDirOut = %MediaSubDirOut% Beta Msgbox, 0,, Beta Mode. All new media stored in %MediaOutPath%\%MediaSubDirOut%, 20 } FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Backglass Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Backglass Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\DMD Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\DMD Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Table Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Table Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Wheel Images ;Start of new XML file if (DragAndDrop<>1) { Progress, x200 y200 zh0 M h200 w600 FS10, `n%WorkingPath%`n %TablePath%`n %Executable%`n`n`n(Press ESC anytime to abort script) , `nWorking on %XMLFileName%.xml, System XML #%A_Index% of %VPXMLCount% ... , Arial Sleep 2000 } ; Clean up ;========================== FileDelete, %A_ScriptDir%\playfield.mkv FileDelete, %A_ScriptDir%\bg.mkv FileDelete, %A_ScriptDir%\dmd.mkv Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel Progress, Off ;*************** Screensize check - How good is your screenres.txt **************** ;========================== SysGet, VirtualScreenWidth, 78 TotalScreenWidth := DMD_X + DMD_width DMD_oldwidth := DMD_Width PFBGWidth := PF_width+BG_width ;Convert all width and height to even values for best recording success PF_width := (floor(PF_width/2))*2 PF_height := (floor(PF_height/2))*2 BG_width := (floor(BG_width/2))*2 BG_height := (floor(BG_height/2))*2 DMD_width := (floor(DMD_width/2))*2 DMD_height := (floor(DMD_height/2))*2 FileAppend, `nValues used for media capture (height/width forced to even values)`n, %A_ScriptDir%\PBXrecorder.log FileAppend, VirtualScreenWidth = %VirtualScreenWidth%`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, TotalScreenWidth = %TotalScreenWidth% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, PF_width = %PF_width% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, PF_height = %PF_height% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, BG_width = %BG_width% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, BG_height = %BG_height% `n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_width = %DMD_width% `n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_height = %DMD_height% `n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_X_offset = %XDMD_X% `n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_Y_offset = %DMD_Y% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, -----------------------------------------`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_tot_offset = %DMD_X% `n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, DMD_orig_width = %DMD_oldwidth% `n, %A_ScriptDir%\PBXrecorder.log ;PF width check If ((PF_width > VirtualScreenWidth) and (PFVideoOnly = 1 or PFImageOnly = 1)) { Msgbox, 0, CabCalibration.xml: Playfield size check, Warning: CabCalibration.xml Playfield(%PF_width%) width exceeds the actual size of the windows desktop(%VirtualScreenWidth%). Review Cab Calibration settings`n`nPlayfield recording may not work, 60 FileAppend, WARNING: CabCalibration.xml Playfield width exceeds the actual size of windows desktop. Review Cab Calibration settings`n, %A_ScriptDir%\PBXrecorder.log } ;PF and BG width check If ((PFBGWidth > VirtualScreenWidth) and (BGVideoOnly = 1 or BGImageOnly = 1)) { Msgbox, 0, CabCalibration.xml: Backglass size check, Warning: CabCalibration.xml Playfield(%PF_width%) plus Backglass(%BG_width%) width exceeds the actual size of windows desktop (%VirtualScreenWidth%). Review Cab Calibration settings`n`nBackglass recording may not work, 60 FileAppend, WARNING: CabCalibration.xml Playfield(%PF_width%) plus Backglass(%BG_width%) width exceeds the actual size of windows desktop (%VirtualScreenWidth%). Review Cab Calibration settings`n, %A_ScriptDir%\PBXrecorder.log } ;PF and BG and DMD width check ; If ((TotalScreenWidth > VirtualScreenWidth) and (DMDVideoOnly = 1 or DMDImageOnly = 1)) ; { ; DMD_Width := (floor((DMD_oldwidth - (TotalScreenWidth - VirtualScreenWidth))/2))*2 ; Msgbox, 0, ScreenRes.txt: DMD size check, Warning: Screenres.txt DMD width/offset is not correct`nReducing DMD width from %DMD_oldwidth% to %DMD_width%. Review screenres.txt settings`n`nDMD recording may not work, 60 ; FileAppend, WARNING: DMD window settings incorrect - auto-resizing (%DMD_oldwidth% to %DMD_width%). Review screenres.txt DMD settings`n, %A_ScriptDir%\PBXrecorder.log ; } ;Open XML file and walk through every table ;========================== ExecutableBackup:=Executable PrintFFMPEGExamples:=1 Loop, Read, %XMLPath%\%XMLFilename%.xml { IfInString, A_LoopReadLine, game name= { TableEnabled := 1 Executable:=ExecutableBackup StringGetPos, start, A_LoopReadLine, = StringGetPos, end, A_LoopReadLine, > XTable := SubStr(A_LoopReadLine, start+3, end-start-3) ;Msgbox, what%XTable%`n%A_LoopReadLine%`n%start%`n%end% ;----------------------------------------------------- ;Convert special chars in Table Name so they are used correctly ;----------------------------------------------------- ;Special handling for ® in the Table Name. Change ® to ® IfInString, XTable, ® { StringGetPos, start, XTable, ® TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+2) XTable = %TestTable%%TestTable2% ;msgbox %XTable% } ;Special handling for & in the Table Name. Change & to & IfInString, XTable, & { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+6) XTable = %TestTable%&%TestTable2% } ;Special handling for Italian ® in the Table Name. Change ® to ® IfInString, XTable, ® { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+7) XTable = %TestTable%�%TestTable2% } ;Special handling for italian ' in the Table Name. Change ’ to ' IfInString, XTable, ’ { StringGetPos, start, XTable, ’ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+4) XTable = %TestTable%'%TestTable2% } ;Special handling for ™ in the Table Name. Change ™ to ™ IfInString, XTable, ™ { StringGetPos, start, XTable, ™ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+8) XTable = %TestTable%™%TestTable2% } ;Identify if upt IfExist, %TablePath%\%Xtable%\%Xtable%.upt { Table = %XTable%.upt TableExists := 1 } ; Else IfExist, %TablePath%\%Xtable%.vpx ; { ; Table = %XTable%.vpx ; TableExists := 1 ; } Else ;must be vpx file { ; Table = %XTable%.vpx TableExists := 0 } } Else IfInString, A_LoopReadLine, /description { StringGetPos, start, A_LoopReadLine, <description> StringGetPos, end, A_LoopReadLine, </description> Description := SubStr(A_LoopReadLine, start+14, end-start-13) ;---------------------------------------------------- ;Remove invalid chars from Description name like : / \ * ? " < > | ;---------------------------------------------------- IfInString, Description, : { StringGetPos, start, Description, : TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, / { StringGetPos, start, Description, / TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, \ { StringGetPos, start, Description, \ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, * { StringGetPos, start, Description, * TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, * { StringGetPos, start, Description, * TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+6) Description = %TestTable%%TestTable2% } IfInString, Description, ? { StringGetPos, start, Description, ? TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, " { StringGetPos, start, Description, " TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, < { StringGetPos, start, Description, < TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, > { StringGetPos, start, Description, > TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, | { StringGetPos, start, Description, | TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } ;----------------------------------------------------- ;Convert special chars in Description so they are used correctly ;----------------------------------------------------- ;Special handling for ® in the Description. Change ® to ® IfInString, Description, ® { StringGetPos, start, Description, ® TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } ;Special handling for & in the Description. Change & to & IfInString, Description, & { StringGetPos, start, Description, & TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+6) Description = %TestTable%&%TestTable2% } ;Special handling for ® in the Description. Change ® to ® IfInString, Description, ® { StringGetPos, start, Description, ® TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+7) Description = %TestTable%�%TestTable2% } ;Special handling for italian ' in the Description. Change ’ to ' IfInString, Description, ’ { StringGetPos, start, Description, ’ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+4) Description = %TestTable%'%TestTable2% } ;Special handling for ™ in the Description. Change ™ to ™ IfInString, Description, ™ { StringGetPos, start, Description, ™ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+8) Description = %TestTable%™%TestTable2% } FileAppend, `n%Description%`n, %A_ScriptDir%\PBXrecorder.log If TableExists = 0 FileAppend, Table file not found: %TablePath%\%XTable%\%XTable%.upt `n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, /alternateExe { StringGetPos, start, A_LoopReadLine, <alternateExe> StringGetPos, end, A_LoopReadLine, </alternateExe> Executable := SubStr(A_LoopReadLine, start+15, end-start-14) ;Msgbox, %Executable% FileAppend, AlternateExe found in xml: %Executable%`n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, /exe { StringGetPos, start, A_LoopReadLine, <exe> StringGetPos, end, A_LoopReadLine, </exe> Executable := SubStr(A_LoopReadLine, start+6, end-start-5) ;Msgbox, %Executable% FileAppend, Exe found in xml: %Executable%`n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, enabled>False { ;Msgbox, %A_LoopReadLine% FileAppend, Table disabled in xml: %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log TableEnabled := 0 } Else IfInString, A_LoopReadLine, enabled>True { ;Msgbox, %A_LoopReadLine% TableEnabled := 1 } Else IfInString, A_LoopReadLine, /game { If TableEnabled = 1 { If TableExists = 1 { Loopcount:=Loopcount + 1 ;Msgbox, recording ;Check if Media Files exist and skip if skip is enabled ;=================================================== MediaFoundFlag:=0 If (MediaFileNaming=0) SearchString:=Description Else SearchString:=Xtable If (PrintFFMPEGExamples=1) { PrintFFMPEGExamples:=0 FileAppend, `nEXAMPLE of all ffmpeg.exe commands used`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vf "rotate=PI:bilinear=0" "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\playfield.mkv" -ss 5 -to 1000 -vf [in]rotate=PI:bilinear=0[middle];[middle]scale=1920:-1[out] -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\bg.mkv" -ss 5 -to 1000 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\dmd.mkv" -ss 5 -to 1000 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%"`n`n, %A_ScriptDir%\PBXrecorder.log } If ((OnlyRecordMissingVideos = 1) or (OnlyRecordMissingVideos = 2) or (OnlyRecordMissingVideos = 3)) { ;Perform media check for missing files MediaFoundFlag:=1 MediaAtLeastOneFound:=0 If (PFVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Videos\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: Table Video`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (BGVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Videos\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: BackGlass Video`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } ; If (DMDVideoOnly=1) ; { ; IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Videos\%SearchString%.* ; { ; FileAppend, MISSING: DMD Video`n, %A_ScriptDir%\PBXrecorder.log ; If DMD_width > 0 ; { ; MediaFoundFlag:=0 ; } ; } ; Else ; { ; MediaAtLeastOneFound:=1 ; } ; } If (PFImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Images\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: Table Image`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (BGImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Images\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: BackGlass Image`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } ; If (DMDImageOnly=1) ; { ; IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Images\%SearchString%.* ; { ; FileAppend, MISSING: DMD Image`n, %A_ScriptDir%\PBXrecorder.log ; If DMD_width > 0 ; { ; MediaFoundFlag:=0 ; } ; } ; Else ; { ; MediaAtLeastOneFound:=1 ; } ; } } ;end of If ((OnlyRecordMissingVideos = 1) or (OnlyRecordMissingVideos = 2) or (OnlyRecordMissingVideos = 3)) Else { FileAppend, PBXrecorder set to record complete media set`n, %A_ScriptDir%\PBXrecorder.log } ;=========================================================================== ; Extra Unit3D file checks - DirectB2S and Wheel images (FTP download supported) ;=========================================================================== ;Print out message to log file if DirectB2s file is missing ; IfNotExist, %TablePath%\%XTable%.directb2s ; { ; IfNotExist, %TablePath%\%XTable%.exe ; { ; FileAppend, FYI: No DirectB2S/B2S.exe File. %TablePath%\%XTable%.directb2s`n, %A_ScriptDir%\PBXrecorder.log ; } ; Else ; { ; FileAppend, FYI: No DirectB2S but B2S was found. %TablePath%\%XTable%.directb2s`n, %A_ScriptDir%\PBXrecorder.log ; } ; } ;Print out message to log file if Wheel image is missing - Perform FTP IfNotExist, %MediaOutPath%\%MediaSubDir%\Wheel Images\%Description%.png { ;============================================================= ; Download Wheel from PinballX FTP if user has filled in FTP login info ;============================================================= IfExist, %A_ScriptDir%\FTPLoginInfo.txt { FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 2 IfNotInString, tempStr, USERNAME { Progress, x200 y200 zh0 M h200 w600 FS10, `n`Wheel Image missing... Check PinballX FTP site`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Attempting PinballX FTP download , Arial ;Strip out the {...} from the description if found StringSplit, SearchStringArray, Description, {} ;drop the 2nd part SearchStringArray1:=Trim(SearchStringArray1) SearchStringArray3:=Trim(SearchStringArray3) If (StrLen(SearchStringArray3)>0) SearchStringArray1=%SearchStringArray1% %SearchStringArray3% FileToGet = %SearchStringArray1%.png FileDelete %A_ScriptDir%\FTPtemp.bat FileAppend, open online.gameex.com`n, %A_ScriptDir%\FTPtemp.bat FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 2 FileAppend, %tempStr%`n, %A_ScriptDir%\FTPtemp.bat FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 3 FileAppend, %tempStr%`n, %A_ScriptDir%\FTPtemp.bat FileAppend, ( binary hash cd "/-PinballX-/Media/Visual Pinball/Wheel Images" get "%FileToGet%" bye ), %A_ScriptDir%\FTPtemp.bat RunWait %comspec% /c ftp.exe -s:"%A_ScriptDir%\FTPtemp.bat" FileDelete %A_ScriptDir%\FTPtemp.bat FileMove %A_ScriptDir%\%FileToGet%, %MediaOutPath%\%MediaSubDirOut%\Wheel Images\%Description%.png, 1 IfNotExist, %MediaOutPath%\%MediaSubDirOut%\Wheel Images\%Description%.png { FileAppend, FYI (Wheel not found in FTP): No Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } Else { FileAppend, Downloaded via FTP: Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, FYI (FTP not enabled): No Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, FYI (FTP not enabled): No Wheel Image - %SearchString%.png`n, %A_ScriptDir%\PBXrecorder.log } } ; END OF Extra VP file checks - DirectB2S and Wheel images (FTP download supported) ;=========================================================================== ; Media checked - Decide whether to record or skip table ;=========================================================================== IfEqual MediaFoundFlag, 1 ;If all media exists then skip table { If PauseTime>=10 PauseTime:=PauseTime-5 TempLongPath = %TablePath%\%XTable%\%Table% if (DragAndDrop<>1) { Progress, x200 y200 zh0 M h200 w600 FS10, `nMedia already exists. Skipping...`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Capturing Videos... #%Loopcount% , Arial Sleep %PauseTime% FileAppend, Skipping table... %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } Else If inStr(TempLongPath, DragAndDropFile) ;Check if drag and drop table already has media { DragAndDropTableFound := -1 Progress, x200 y200 zh0 M h200 w600 FS10, `nDrag and Drop table media already exists. Skipping...`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Drag and Drop... #%Loopcount% , Arial Sleep 3000 FileAppend, Drag and drop table already has Media. Skipping... %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } continue ;Skipping table!!! } Else If (DragAndDrop=1) ;and MediaFoundFlag = 0 ;Handle Drag and drop table recording { ;Check if current table matches the drag and drop table TempLongPath = %TablePath%\%XTable%\%Table% If inStr(TempLongPath, DragAndDropFile) ;Match - go ahead and record { DragAndDropTableFound := 1 Progress, x200 y200 M h240 w600 FS10 CB0000FF, `n`nLoading "%Table%"`n`nDrag and Drop recording will start in %LoadTime% seconds...`n(Press PAUSE if you need to edit/setup table)`n(Press ESC anytime to abort script) ,`n`n%Description%`n, Capturing Videos... #%Loopcount% , Arial FileAppend, Launching table: %XTablePath%\Unit3D Pinball.exe %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } Else ;No match - skip this table { FileAppend, Skipping table due to Drag and Drop mode... %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log continue ;Skipping table } } Else If ((OnlyRecordMissingVideos=3) and (MediaAtLeastOneFound=1)) ;check if Mode = Record ONLY new tables(Ignore partial media set) AND any if media was found { FileAppend, Skipping table - Recording only new tables. Partial media set exists... %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log continue ;Skipping table } Else ;MediaFoundFlag = 0 ;Launch table to record { Progress, x200 y200 M h240 w600 FS10 CB0000FF, `n`nLoading "%Table%"`n`nRecording will start in %LoadTime% seconds...`n(Press PAUSE if you need to edit/setup table)`n(Press ESC anytime to abort script) ,`n`n%Description%`n, Capturing Videos... #%Loopcount% , Arial FileAppend, Launching table: %XTablePath%\Unit3D Pinball.exe %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } ;================================================= ;Start Table ;================================================= Recordcount:=Recordcount + 1 Run, "%XTablePath%\Unit3D Pinball.exe" "%TablePath%\%XTable%\%Table%" Process, wait, Unit3D Pinball.exe LoadingTable:=1 If (TestMode=1) ;debug speed up of recording { Loop, 50 ;DEBUG { j := A_Index/1.0 Progress,%j% Sleep 100 If (PBXRPauseMode=1) { Goto, PBRXPaused } } ; Allow time for table score display to get well beyond loading and boot images } Else { Loop, % LoadTimeX ; { j := A_Index/LoadTimeX*100 Progress,%j% Sleep 100 If (PBXRPauseMode=1) { Goto, PBRXPaused } } ; Allow time for table score display to get well beyond loading and boot images } Progress, Off LoadingTable:=0 PBRXPaused: If (LoadingTable=1) ;User has paused PBX Recorder { Progress, Off WindowX:=PF_width/2 -200 Progress, x%WindowX% y0 h25 w400 FS10 CB0000FF, Paused. Press Pause key to start recording , Paused. Press Pause key to start recording, Press Pause to Resume , Arial WinWaitClose, Press Pause to Resume } LoadingTable:=0 PBXRPauseMode:=0 ; Record Video as .mkv - Fast Capture and take screenshots ;============================================================ FileAppend, Video and screenshot capture (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log If (OnlyRecordMissingVideos = 2) ;Mode = RECORD MISSING MEDIA ONLY ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { If (PFImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Images\%SearchString%.* { Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vf "rotate=PI:bilinear=0" "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png",,Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } If (BGImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Images\%SearchString%.* { Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png",,Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } ; If (DMDImageOnly=1) ; { ; If DMD_width > 0 ; { ; IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Images\%SearchString%.* ; { ; Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png",,Hide ; FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } ; Else ; { ; FileAppend, Screenshot skipped (Bad DMD size) "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } Sleep,3000 If (PFVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Videos\%SearchString%.* { ;Run, %FFMPEG_Path%\ffmpeg -y -t %RecTime% -rtbufsize 1500M -f dshow -i audio=%Audio_Device% -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -acodec copy -threads 8 "%A_ScriptDir%\playfield.mkv",,Hide Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\playfield.mkv",,Hide FileAppend, Recording "%A_ScriptDir%\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } If (BGVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Videos\%SearchString%.* { Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\bg.mkv",,Hide FileAppend, Recording "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } ; If (DMDVideoOnly=1) ; { ; If DMD_width > 0 ; { ; IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Videos\%SearchString%.* ; { ; Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\dmd.mkv",,Hide ; FileAppend, Recording "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } ; Else ; { ; FileAppend, Recording skipped (Bad DMD size) "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } } Else If ((OnlyRecordMissingVideos=3) and (MediaAtLeastOneFound=1)) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { ;Safety check for Mode = Record only new tables (Ignore partial media set). FileAppend, Skipping table - XXX Recording only new tables. Partial media set exists... %TablePath%\%XTable%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } Else ;Record everything for this table (Mode = Re-record all, Record if incomplete table, Record if new table) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { If (PFImageOnly=1) { Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vf "rotate=PI:bilinear=0" "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png",,Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } If (BGImageOnly=1) { Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png",,Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } ; If (DMDImageOnly=1) ; { ; If DMD_width > 0 ; { ; Run, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png",,Hide ; FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; } ; Else ; { ; FileAppend, Screenshot skipped (Bad DMD size) "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } Sleep,3000 If (PFVideoOnly=1) { ;Run, %FFMPEG_Path%\ffmpeg -y -t %RecTime% -rtbufsize 1500M -f dshow -i audio=%Audio_Device% -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -acodec copy -threads 8 "%A_ScriptDir%\playfield.mkv",,Hide Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\playfield.mkv",,Hide FileAppend, Recording "%A_ScriptDir%\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log } If (BGVideoOnly=1) { Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\bg.mkv",,Hide FileAppend, Recording "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log } ; If (DMDVideoOnly=1) ; { ; If DMD_width > 0 ; { ; Run, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\dmd.mkv",,Hide ; FileAppend, Recording "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; } ; Else ; { ; FileAppend, Recording skipped (Bad DMD size) "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; } ; } } WinActivate, ahk_class UnityWndClass WinWaitActive, ahk_class UnityWndClass,,5 ; Clean up ;========================== Process, WaitClose, ffmpeg.exe, 500 WinMinimize, ahk_class UnityWndClass WinClose, ahk_class UnityWndClass WinWaitClose ahk_class UnityWndClass Run, taskkill /T /IM "Unit3D Pinball.exe" ,,UseErrorLevel ; Run, taskkill /T /IM B2SBackglassServerEXE.exe,,UserErrorLevel ; Run, taskkill /F /IM %XTable%.exe,,UserErrorLevel ; IfInString, XTable, B2S.exe, WinKill, Form1 Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel Run, taskkill /IM ffmpeg.exe /F,,UseErrorLevel ; Run, taskkill /F /IM UltraDMD.exe,,UseErrorLevel ; Run, taskkill /F /IM Pin2dmd.exe,,UseErrorLevel Sleep,5000 Run, taskkill /F /IM "Unit3D Pinball.exe",,UseErrorLevel ; Run, taskkill /F /IM B2SBackglassServerEXE.exe,,UserErrorLevel ; WinKill, UltraDMD WinKill, Error ;PIN2DMD related - Not ready for primetime yet ;========================== ;IfExist, %A_ScriptDir%\pin2dmd\pin2dmd.exe ;{ ; Run, %A_ScriptDir%\pin2dmd\Pin2DMD.exe /r,,UseErrorLevel ;} ;IfExist, %A_ScriptDir%\pin2dmd\blank.ppm ;{ ; Run, %A_ScriptDir%\pin2dmd\Pin2DMD.exe /i %A_ScriptDir%\pin2dmd\blank.ppm,,UseErrorLevel ;} ;Convert Videos to .f4v/.mp4 if any mkv exist - Post Capture Trim and Transcode ;============================================================================ Progress, x200 y200 zh0 M h200 w600 FS10, `n`nConvert Videos to %RecExt% if video was captured`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Capturing Videos... #%Loopcount% , Arial ConvertStatusStr= ( If (PFVideoOnly=1) ConvertStatusStr= %ConvertStatusStr% PF If (BGVideoOnly=1) ConvertStatusStr= %ConvertStatusStr% BG ; If (DMDVideoOnly=1) ; ConvertStatusStr= %ConvertStatusStr% DMD ConvertStatusStr= %ConvertStatusStr% ) FileAppend, Convert Videos to %RecExt% if video was captured (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log IfExist, %A_ScriptDir%\playfield.mkv ;If (PFVideoOnly=1) ; { Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\playfield.mkv" -ss 5 -to 1000 -vf [in]rotate=PI:bilinear=0[middle];[middle]scale=1920:-1[out] -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%" FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log } IfExist, %A_ScriptDir%\bg.mkv ;If (BGVideoOnly=1) ; { Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\bg.mkv" -ss 5 -to 1000 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%" FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log } ; IfExist, %A_ScriptDir%\dmd.mkv ;If (DMDVideoOnly=1) ; ; { ; Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\dmd.mkv" -ss 5 -to 1000 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%" ; FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log ; } ; Clean up ;========================== Process, WaitClose, ffmpeg.exe, 500 Run, taskkill /IM ffmpeg.exe /F Run, taskkill /IM ffmpeg.exe /F Run, taskkill /IM ffmpeg.exe /F Progress, Off Sleep,3000 ;SoundBeep, 400, 200 FileDelete, %A_ScriptDir%\playfield.mkv FileDelete, %A_ScriptDir%\bg.mkv FileDelete, %A_ScriptDir%\dmd.mkv FileAppend, Table done (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log } ;End of If TableExists = 1 } ;End of If TableEnabled = 1 } ;End of Else IfInString, A_LoopReadLine, /game } ;End of Loop, Read, %XMLPath%\%XMLFilename%.xml } ; All done! ;=============== Progress, Off If (DragAndDrop<>1) { FileAppend, `n%Recordcount% new recordings out of %Loopcount% tables. Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Recording Finished,Recording is complete. %Recordcount% new recordings out of %Loopcount% tables } Else ;Drag and drop done { If (DragAndDropTableFound=1) { FileAppend, `nDrag and Drop recording finished (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, Recording is complete`n`n(%DragAndDropFile%). } Else If (DragAndDropTableFound=-1) { FileAppend, `nDrag and Drop skipped. Media already exists (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, No Recording. Media already exists`n`n(%DragAndDropFile%). } Else { FileAppend, `nDrag and Drop table was not found in the Unit3D XML files (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, Table was not found in the Unit3D XML files. No recording performed`n`n(%DragAndDropFile%). } } ExitApp ;******************************************* ;******************************************* ; Misc Subroutines for Msgbox and Gui windows and Exit ;******************************************* ;******************************************* RecordModeButtonNames: IfWinNotExist, Record Mode return ; Keep waiting. SetTimer, RecordModeButtonNames, off WinActivate ControlSetText, Button1, &Videos Only ControlSetText, Button2, &Both return MissingVideosButtonNames: IfWinNotExist, Record Mode return ; Keep waiting. SetTimer, MissingVideosButtonNames, off WinActivate ControlSetText, Button1, &Missing Only ControlSetText, Button2, &All Tables return CurrSettingsButtonNames: IfWinNotExist, Current Recorder Settings return ; Keep waiting. SetTimer, CurrSettingsButtonNames, off WinActivate ControlSetText, Button1, &Continue ControlSetText, Button2, &Change return StoreMediaButtonNames: IfWinNotExist, Storing Media return ; Keep waiting. SetTimer, StoreMediaButtonNames, off WinActivate ControlSetText, Button1, &Combined ControlSetText, Button2, &Separate return GuiClose: ExitApp ;Pressing the ESC key will abort the script Esc:: IfWinNotExist,Add Table to XML IfWinNotExist,Press Pause to Resume ExitApp Else Return ; XML dialog present, do not exit Pause:: If (LoadingTable=1) { If (PBXRPauseMode=0) { PBXRPauseMode:=1 } Else { Progress, Off } } Return Confirm: Gui, Submit PFVideoOnly=0 BGVideoOnly=0 DMDVideoOnly=0 PFImageOnly=0 BGImageOnly=0 DMDImageOnly=0 if (PFVid = 1) PFVideoOnly=1 if (BGVid = 1) BGVideoOnly=1 if (DMDVid = 1) DMDVideoOnly=1 if (PFImage = 1) PFImageOnly=1 if (BGImage = 1) BGImageOnly=1 if (DMDImage = 1) DMDImageOnly=1 Gui, Destroy return Select: Gui, Submit if (RadioGroup1) RecTime:=5 else if (RadioGroup2) RecTime:=15 else if (RadioGroup3) RecTime:=30 else if (RadioGroup4) RecTime:=60 else if (RadioGroup5) RecTime:=120 else if (RadioGroup6) RecTime:=300 Gui, Destroy Return MediaMode: Gui, Submit if (MRadioGroup1) OnlyRecordMissingVideos:=2 else if (MRadioGroup2) OnlyRecordMissingVideos:=1 else if (MRadioGroup3) OnlyRecordMissingVideos:=0 else if (MRadioGroup4) OnlyRecordMissingVideos:=3 Gui, Destroy Return MediaF: Gui, Submit if (RadioGroupMF1) MediaFileNaming:=0 else if (RadioGroupMF2) MediaFileNaming:=1 Gui, Destroy Return MediaR: Gui, Submit if (RadioGroupRF1) { RecFormat:=0 RecExt=f4v } else if (RadioGroupRF2) { RecFormat:=1 RecExt=mp4 } Gui, Destroy Return ; Subroutines for Add Table to XML files GetXMLDescSelected: GuiControlGet, XMLDescSelected x:=IPDBArray[XMLDescSelected] GuiControl,, XMLDescText,%x% x:=IPDBMfrArray[XMLDescSelected] GuiControl,, XMLMfr,%x% x:=IPDBYearArray[XMLDescSelected] GuiControl,, XMLYear,%x% x:=IPDBTypeArray[XMLDescSelected] GuiControl,, XMLType,%x% Return XMLLaunch: GuiControlGet, XMLAltExe GuiControlGet, XMLAltExeName If (XMLAltExe = 1) IfExist, %WorkingPath%\%LaunchExecutable% { Run, "%WorkingPath%\%LaunchExecutable%" -play "%DragAndDropFile%",,UseErrorLevel } Else { Msgbox, %WorkingPath%\%LaunchExecutable% could not be found Return } Else IfExist, %WorkingPath%\%XMLAltExeName% Run, "%WorkingPath%\%XMLAltExeName%" -play "%DragAndDropFile%",,UseErrorLevel Else { Msgbox, %WorkingPath%\%XMLAltExeName% could not be found Return } Return XMLCancel: Gui, Destroy ExitApp XMLSaveExit: gosub XMLSave ;Msgbox XML Saved ExitApp XMLSave: ;Figure out which XML file to update GuiControlGet, XMLVPSystem tempXMLString1:=XMLPathArray[XMLVPSystem] tempXMLString2:=XMLFileNameArray[XMLVPSystem] tempXMLStringOrig=%tempXMLString1%\%tempXMLString2%.xml tempXMLStringBak=%tempXMLString1%\%tempXMLString2%.bak ;FileAppend, `t TEST %tempXMLStringOrig%`n, %A_ScriptDir%\XMLtest.txt FileCopy, %tempXMLStringOrig%, %tempXMLStringBak%, 1 FileRead, tempXMLfilestring, %tempXMLStringOrig% StringReplace, tempXMLfilestring, tempXMLfilestring, `r`n</menu> StringReplace, tempXMLfilestring, tempXMLfilestring, `n</menu> FileDelete, %tempXMLStringOrig% FileAppend, %tempXMLfilestring%, %tempXMLStringOrig% GuiControlGet, XMLTableFileName FileAppend, `t<game name="%XMLTableFileName%">`n, %tempXMLStringOrig% GuiControlGet, XMLDescText FileAppend, `t`t<description>%XMLDescText%</description>`n, %tempXMLStringOrig% FileAppend, `t`t<rom></rom>`n, %tempXMLStringOrig% GuiControlGet, XMLMfr FileAppend, `t`t<manufacturer>%XMLMfr%</manufacturer>`n, %tempXMLStringOrig% GuiControlGet, XMLYear FileAppend, `t`t<year>%XMLYear%</year>`n, %tempXMLStringOrig% GuiControlGet, XMLType FileAppend, `t`t<type>%XMLType%</type>`n, %tempXMLStringOrig% GuiControlGet, XMLHideDMD If (XMLHideDMD=1) FileAppend, `t`t<hidedmd>True</hidedmd>`n, %tempXMLStringOrig% Else FileAppend, `t`t<hidedmd>False</hidedmd>`n, %tempXMLStringOrig% GuiControlGet, XMLHideBG If (XMLHideBG=1) FileAppend, `t`t<hidebackglass>True</hidebackglass>`n, %tempXMLStringOrig% Else FileAppend, `t`t<hidebackglass>False</hidebackglass>`n, %tempXMLStringOrig% GuiControlGet, XMLEnabled If (XMLEnabled=1) FileAppend, `t`t<enabled>True</enabled>`n, %tempXMLStringOrig% Else FileAppend, `t`t<enabled>False</enabled>`n, %tempXMLStringOrig% GuiControlGet, XMLRating XMLRating := XMLRating-1 FileAppend, `t`t<rating>%XMLRating%</rating>`n, %tempXMLStringOrig% GuiControlGet, XMLAltExe GuiControlGet, XMLAltExeName If (XMLAltExe = 2) FileAppend, `t`t<alternateExe>%XMLAltExeName%</alternateExe>`n, %tempXMLStringOrig% Else If (XMLAltExe = 3) FileAppend, `t`t<Exe>%XMLAltExeName%</alternateExe>`n, %tempXMLStringOrig% FileAppend, `t</game>`n, %tempXMLStringOrig% FileAppend, </menu>`n, %tempXMLStringOrig% Gui, Destroy Return XMLDB2S: IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S Return Else IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.exe Return Else ;Let user select DirectB2S file to rename FileSelectFile, XMLFilePicked,,%DragAndDropFileDir%,,*.directb2s IfExist, %XMLFilePicked% { SetTimer, DB2SButtonNames, 50 Msgbox, 3, DirectB2S File Rename, Create a copy of the DirectB2S file and rename it? IfMsgBox, Yes ; Copy and rename the file { GuiControl ,, XDB2S, DB2S Found FileCopy, %XMLFilePicked%, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S, 1 } Else IfMsgBox, No ; Just rename the file { FileMove, %XMLFilePicked%, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S, 1 GuiControl ,, XDB2S, DB2S Found } } Return DB2SButtonNames: IfWinNotExist, DirectB2S File Rename return ; Keep waiting. SetTimer, DB2SButtonNames, off WinActivate ControlSetText, Button1, &Copy&&Rename ControlSetText, Button2, &Just Rename return ; Release 1.0 Initial release Nov 11, 2015 ; Create playfield, backglass, dmd videos and/or images automatically based on PinballX setup ; Release 1.1 Fix bug if VisualPinball system is disabled (Dec 2015) ; Release 1.2 Skip table if table is disabled in Game Manager/XML (Jan 9, 2016) ; Add <AlternateExe> and <exe> xml tag support ; Add support for & and ® and ' in Table and Description names ; Check if vpt or vpx file exists, skip if not found ; Detects if Wheel Images or DirectB2S/B2S.exe are missing ; PinballX FTP users can enable automatic Wheel download support ; If PIN2DMD.exe found, it will reset PIN2DMD between tables ; 1.3 changes Feb 7, 2016 ; New recording mode added: "Record complete media set for new tables only" If any media is found, the table is skipped. Only tables with no media are recorded. This might eliminate the need for the drag and drop feature, since this leaves your existing Pinballx Media set unchanged, i.e if you do not have DMD images for some existing tables, PBX Recorder will not try to create them ; Drag and drop .vpt/.vpx file onto PBXrecorder to record only one table (Table must be exist in the PinballX xml files) ; New option to record video in .mp4 or existing .f4v. Now checks for existing .f4v or .mp4 or any file. ; New option to save Media filenames based on description name or table name ; Speed up the scanning of tables for people with larger libraries ; Improve DMD recording success by forcing dvd dimensions to an even pixel value ; Bug fix: Enable recordings for VP xml systems missing the enabled xml tag ; 1.4 changes Apr 7, 2016 ; New dialog to add table to Pinballx XML file ; PAUSE and RESUME support to allow table script changes before recording. Double tap PAUSE to record immediately ; 1.4Unit3D May 12, 2016 ; Port for Unit3D capture - Unit3D beta does not support three screens - DMD settings will be ignored ; Add support for ™ and recognition of * (i.e, *) in Table and Description names ; Some minor clean up for unused ErrorLevel parameters ; Add right click support (Play with VP, Record with PBXRecorder) ;todo: create reg entries ;todo: detect xml file to default to ;todo list duplicates xmls entries. ;todo support [xxx] for wheel download. ;todo list tables not in the xml file ;todo switch ini parsing to use split string function ; possible bug. recext not correct after modifying ini Changes from 1.4 ; 1.4Unit3D May 12, 2016 ; Port for Unit3D capture - Unit3D beta does not support three screens - DMD settings will be ignored ; Add support for ™ and recognition of * (i.e, *) in Table and Description names ; Some minor clean up for unused ErrorLevel parameters Again thanks to gtxjoe for allowing mods to his source code. I've updated PBXRecorder for Unit3D to 1.5 based on gtxjoe's work. Source code and x64 compiled executable attached. ; 1.5Unit3D Sept 18, 2016 ; Port for Unit3D capture - Unit3D beta does not support three screens - DMD settings will be ignored ; Add support for · and recognition of · (i.e, middot as in PIN·BOT) in Table and Description names ; Some minor clean up for unused ErrorLevel parameters I'm still testing PBXRecorder for FP based on using the latest OBS Studio as a capture engine. PBXrecorder_1.5Unit3D.zip 1 Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted October 2, 2016 Author Share Posted October 2, 2016 There is a performance benefit in running the newer versions of VPX in true full screen. Unfortunately, ffmpeg cannot capture the playfield when VP is in true fullscreen. It's pretty easy to use the RegWrite instruction to change to windowed full screen on the fly and then change the registry back to true full screen after the capture is completed. I still run my old capscreens script rather than PBXRecorder because I use a custom xml, but I just change the fullscreen key to zero before capture and to one after capture. Capscreens script attached. CapScreens.zip Quote Link to comment Share on other sites More sharing options...
bent98 Posted November 19, 2016 Share Posted November 19, 2016 I just set this up. One thing I noticed is that it doesnt record Mp4 format even though I selected it. It only records .f4v Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted December 18, 2016 Author Share Posted December 18, 2016 The port of gtxjoe's PBXRecorder v1.5 to support FP is working Ok for me with the current version of FFMPEG and of OBS Studio: https://github.com/jp9000/obs-studio/releases/download/0.16.6/OBS-Studio-0.16.6-Small.zip The install steps documented in this post still apply: x64 compiled executable, updated config folder, and source code attached ; 1.5FP Oct 7, 2016 ; Future Pinball support with playfield capture via OBS Studio ; Add support for · and recognition of · (i.e, middot as in PIN·BOT) in Table and Description names PBXrecorder_1.5FP.zip Quote Link to comment Share on other sites More sharing options...
Xantari Posted February 20, 2017 Share Posted February 20, 2017 I haven't been able to get this to work yet. Program starts to change ball type in Future pinball near end of video, then trys to launch another instance of the hotkey program. I'm thinking the 1.5FP version is missing some items as basic.ini in obs-studio on the BG profile has references to steam.exe and antimicro.exe (not sure what that is) Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted February 21, 2017 Author Share Posted February 21, 2017 I've only tested with the draganddrop feature. Have you tried launching that way? Quote Link to comment Share on other sites More sharing options...
Xantari Posted February 22, 2017 Share Posted February 22, 2017 Not yet, was trying the command line option. I've gotten further with the other capture script you provided. I think the FP1.5 .zip file has a bad basic.ini file in the zip file for the playfield. It isn't formated in JSON, but instead looks like it was another AHK script. Quote Link to comment Share on other sites More sharing options...
Xantari Posted February 23, 2017 Share Posted February 23, 2017 Carny, do you have the FP 1.4 ahk script source? That one mostly works, but I need to see if I can find the issue that prevents it from going to the next table automatically. The FP 1.5 version isn't working, and haven't had time to add a bunch of debugging statments to it, but the FP 1.4 version almost works for me. Thanks! Quote Link to comment Share on other sites More sharing options...
Xantari Posted February 25, 2017 Share Posted February 25, 2017 So I got the FP 1.5 version to work, however this section doesn't close FP for me: WinHide, ahk_class FuturePinball WinMinimize, ahk_class FuturePinball WinActivate, ahk_class FuturePinballOpenGL WinWaitActive, ahk_class FuturePinballOpenGL Send {Esc} WinWaitClose, ahk_class FuturePinballOpenGL,,, 5 This should conceivably close future pinball, but it does not. Quote Link to comment Share on other sites More sharing options...
chrisseear Posted February 25, 2017 Share Posted February 25, 2017 Spent about a week trying to get this to work, gave up after I almost killed my-self I use GTXjoes to record VP tables all the time and it never fails, I actually wish this worked more because its harder to find the media for future pinball tables. I'll keep checking back for a never version. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted February 25, 2017 Author Share Posted February 25, 2017 So I got the FP 1.5 version to work, however this section doesn't close FP for me: WinHide, ahk_class FuturePinball WinMinimize, ahk_class FuturePinball WinActivate, ahk_class FuturePinballOpenGL WinWaitActive, ahk_class FuturePinballOpenGL Send {Esc} WinWaitClose, ahk_class FuturePinballOpenGL,,, 5 This should conceivably close future pinball, but it does not. I pulled this chunk of code directly from FPLaunch. Strange that it isn't closing it. What process is still open? Sent from my iPhone using Tapatalk Quote Link to comment Share on other sites More sharing options...
Xantari Posted February 25, 2017 Share Posted February 25, 2017 I think I figured it out. Though I'm not sure what specific change I did. Here is what I did: 1. All .EXE's in Future Pinball folder, set to administrator 2. All OBS exe's, set to administrator 3. Set all FFMPEG .exe's to Administrator 4. Set the C:\Program files, autohotkey program to always run as administrator (all .exes). Since I was launching via the .ahk instead of .exe 5. Set the timeout before table load to a longer value (25 seconds instead of 15 seconds) 6. Added many more logging statements to the ahk file 7. Installed latest OBS Studio and setup those profiles which also got stored in %appdata%, however I believe it still uses the C:\obs-studio\config folder instead when launched in --portable mode 8. Copied futuredmd.exe to BAM folder (even though BAM worked OK with it in the Future Pinball main folder. One or more of those steps seems to have solved it. Not sure which one though. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted February 25, 2017 Author Share Posted February 25, 2017 I always forget to mention it. Anything dealing with the pinball setup, all exe should be set to run as administrator. You may wind up having to go with a longer load delay with the really huge tables. I just set to 60 seconds as a default. I think it would probably be better to setup OBS profiles running off of --portable to ensure that settings are stored in the correct location. But it's good if something has changed so that OBS now reads the config files from either location. You might check your path to futuredmd.exe, but, hey, if it's working now. Glad you got it figured out. Quote Link to comment Share on other sites More sharing options...
GatorCoop Posted May 16, 2017 Share Posted May 16, 2017 On 5/2/2016 at 2:53 AM, Carny_Priest said: Hi, the latest OBS studio added command line support for multiple profiles, so I ported gtxjoe's version 1.4 to support capturing Future Pinball tables. It has all the features of 1.4 except that it supports only Future Pinball and uses OBS Studio as the capture engline for playfield, backglass, DMD. Ffmpeg is still required to complete the transcode to generate the final output. Latest OBS Studio for Windows (portable zip): https://github.com/jp9000/obs-studio/releases/download/0.14.1/OBS-Studio-0.14.1.zip The installation contains both 32bit and 64bit executables. The script assumes 64bit and assumes that you will extract directly to your C: drive. Unzip the following file into the obs-studio folder, RETAIN THE FOLDER STRUCTURE WHEN YOU COPY https://dl.dropboxusercontent.com/u/45430846/config.zip Open a command prompt and navigate to obs-studio\bin\64bit execute obs64.exe --portable Agree to the license. There are pre-existing profiles, scene collections, and sources for playfield, bg, and dmd. Each source captures an entire screen. You may want to confirm that each profile is capturing the correct screen. Click the settings icon for display capture in each profile and see that the preview is displaying the correct screen. You can change the screen using the pulldown menu. The script assumes that full screens are used for playfield and bg. Ffmpeg will automatically crop the DMD video based on your FutureDMD settings. I think that's it. The 64bit compiled executable is here: https://dl.dropboxusercontent.com/u/45430846/PBXrecorder_x64_1.4FP.exe As always, run as admin. This can co-exist in the same folder as PBXRecorder for VP. The log will get overwritten but it creates an ini file with a different file name. Output will look best and work trouble free with the LAV filters that are linked on the PinballX home page. Because of the length of time it takes to load some of the more elaborate tables in my cab, I've increased the wait time from 15 seconds to 60 seconds. It's simply what it takes on my system to load SlamT1lt's Nightmare on Elm Street and Robocop. I'm running FP at 3K using NVidea DSR on a GTX 660. Using the same capturing engine, the videos are synced up better than when I was using a mix of OBS and ffmpeg. But my hardware is three years old now and running all of these capture simultaneously causes slowdown, so this may require some beefy hardware, or you might try capturing the different screens in separate sessions. I'm assuming if you are capturing three screens that you are using FutureDMD. I'm not aware of another solution. Capture settings are read from the registry and FutureDMD.ini. No sense trying to capture anything until you are sure the tables are playing correctly. Works with or without BAM. Why would you not use BAM, though? Source: Hide contents ;PBX recorder 1.4FP (May 2, 2016) - Mod by Carny_Priest from original 1.4 by GTXJoe LoadTime:= 60 ;How long to allow table to load/start (in sec) ;*****Start log file FileDelete %A_ScriptDir%\PBXrecorder.log FileAppend, %A_MMMM% %A_DD%`,%A_YYYY% %A_Hour%:%A_Min%:%A_Sec%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, Version 1.4betaFP`n, %A_ScriptDir%\PBXrecorder.log ;*******If table drag and drop use, record only that table ************************* Loop %0% { GivenPath := %A_Index% Loop %GivenPath%, 1 { DragAndDropFile = %A_LoopFileLongPath% } SplitPath, DragAndDropFile, DragAndDropFileName, DragAndDropFileDir, DragAndDropFileExtOnly, DragAndDropFileNameOnly If ((InStr(DragAndDropFileExtOnly, "fpt")) = 1) DragAndDrop := 1 ; Else If ((InStr(DragAndDropFileExtOnly, "vpx")) = 1) ; DragAndDrop := 1 Else { Msgbox Error: %DragAndDropFileName% is not a Future Pinball table ExitApp } FileAppend, Drag and Drop used: %DragAndDropFile%`n, %A_ScriptDir%\PBXrecorder.log DragText = --------------------------- Drag and drop mode ---------------------------`n%DragAndDropFileName%`n------------------------------------------------------------------------------ Break } ;***************Monitor setup details SysGet, MonitorCount, MonitorCount SysGet, MonitorPrimary, MonitorPrimary FileAppend, `nMonitor Count: %MonitorCount%`, Primary Monitor: %MonitorPrimary%`n, %A_ScriptDir%\PBXrecorder.log Loop, %MonitorCount% { SysGet, MonitorName, MonitorName, %A_Index% SysGet, Monitor, Monitor, %A_Index% SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index% ;MsgBox, Monitor %A_Index%: %MonitorRight%x%MonitorBottom% (%MonitorName%) FileAppend, Monitor %A_Index%: %MonitorRight%x%MonitorBottom% (%MonitorName%)`n, %A_ScriptDir%\PBXrecorder.log } ;************************************************************************************************ ;************************************************************************************************ ;Create/Load PinballX recorder settings ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ Version:=5 NumOfSettings:=12 LoadTimeX:=LoadTime*10 PBXRPauseMode:=0 BetaMode:=0 ;0=Normal mode, 1=Beta mode will store recorded media in a Beta folder ;Load PBXrecorder settings if they exist IfExist, %A_ScriptDir%\PBXrecorderFP.ini { ;Load Existing settings from file ;************************* Loopcount:=0 Loop, Read, %A_ScriptDir%\PBXrecorderFP.ini { If (Loopcount = 0) VersionRead:= A_LoopReadLine Else If (Loopcount=1) PinballXPath := A_LoopReadLine Else If (Loopcount=2) OnlyRecordMissingVideos := A_LoopReadLine Else If (Loopcount=3) PFVideoOnly := A_LoopReadLine Else If (Loopcount=4) BGVideoOnly := A_LoopReadLine Else If (Loopcount=5) DMDVideoOnly := A_LoopReadLine Else If (Loopcount=6) PFImageOnly := A_LoopReadLine Else If (Loopcount=7) BGImageOnly := A_LoopReadLine Else If (Loopcount=8) DMDImageOnly := A_LoopReadLine Else If (Loopcount=9) RecFormat := A_LoopReadLine Else If (Loopcount=10) RecTime := A_LoopReadLine Else If (Loopcount=11) MediaFileNaming := A_LoopReadLine Loopcount:=Loopcount + 1 } ;Check Version of ini file ;************************* If ((Version=VersionRead) and (LoopCount=NumOfSettings)) ;If ini version matches, process, else force user to update settings { ;Display ini settings ;************************* If (OnlyRecordMissingVideos = 2) TempStr2 := "`nFind and record missing media files only`n(Existing media files are kept)" Else If (OnlyRecordMissingVideos = 1) TempStr2 := "`nRecord complete media set for new and incomplete tables`n(Incomplete media sets are deleted/re-recorded)" Else If (OnlyRecordMissingVideos = 3) TempStr2 := "`nRecord complete media set for new tables only`n(If any media is found, the table is skipped. Tables with no media are recorded)" Else TempStr2 := "`nStart over and record complete media sets for all tables`n(All existing media is replaced)" If RecFormat = 1 RecExt=mp4 Else RecExt=f4v TempStr1 = `nMedia to Record (%RecTime% sec %RecExt% videos):`n If (PFVideoOnly=1) TempStr1 = %TempStr1%Playfield Videos`n If (BGVideoOnly=1) TempStr1 = %TempStr1%Backglass Videos`n If (DMDVideoOnly=1) TempStr1 = %TempStr1%DMD Videos`n If (PFImageOnly=1) TempStr1 = %TempStr1%Playfield Images`n If (BGImageOnly=1) TempStr1 = %TempStr1%Backglass Images`n If (DMDImageOnly=1) TempStr1 = %TempStr1%DMD Images`n If (MediaFileNaming=0) TempStr1 = %TempStr1%`nMedia filename based on Description tags`n Else TempStr1 = %TempStr1%`nMedia filename based on FP table filename`n If (DragAndDrop<>1) ; if drag and drop not used, display settings { ;Prompt user if change to settings desired ;************************* SetTimer, CurrSettingsButtonNames, 50 Msgbox, 4, Current Recorder Settings, %DragText%`n`nPinballX Path: %PinballXPath%`n%TempStr2%`n%TempStr1%`n`n`nPress ESC to abort script IfMsgBox, NO Change := 1 } } Else { Msgbox, New version of the video recorder detected. Please update settings Change := 1 } } Else ;No PBXRecorderFP.ini found. Need to Create the ini file { ;******* PBXR settings needed ****************** Change := 1 PinballXPath = C:\PinballX } ;*****Create Pinballx.net FTP login file if not exist IfNotExist, %A_ScriptDir%\FTPLoginInfo.txt { FileAppend, **** To enabled Wheel Image downloads - Replace USERNAME and PASSWORD with your Pinballx FTP login info (requires subscription)`n, %A_ScriptDir%\FTPLoginInfo.txt FileAppend, USERNAME`n, %A_ScriptDir%\FTPLoginInfo.txt FileAppend, PASSWORD`n, %A_ScriptDir%\FTPLoginInfo.txt } ; User needs to update PBX Recorder ini settings ;************************* If (Change = 1) { ;Pinballx folder Msgbox, 4,PBXrecorder Settings, PinballX folder: %PinballXPath%`n`n Do you want to change the Pinballx path? `n IfMsgBox Yes ;display folder selection dialog { FileSelectFolder, PinballXPath,,0,Select the Pinballx Folder PinballXPath := RegExReplace(PinballXPath, "\\$") } ;Pic Record Mode Gui, Show, W810 H170, Record Mode gui, font, s10, Arial Gui, Add, Radio, checked vMRadioGroup1, Find and record missing media files only (Existing media files are kept. No files deleted) Gui, Add, Radio, vMRadioGroup4, Record complete media set for new tables only (If any media is found, the table is skipped. Only tables with no media are recorded) Gui, Add, Radio, vMRadioGroup2, Record complete media set for new and incomplete tables (Missing media is recorded. Incomplete media sets are deleted/re-recorded) Gui, Add, Radio, vMRadioGroup3, Start over and record complete media sets for all tables (All existing media is deleted and re-recorded) Gui, Add, Text,, `n Gui, Add, Button, Default gMediaMode, Next Gui, Show WinWaitClose, Record Mode ;Choose what media to record Gui, Show, W400 H280, Choose Media to Record gui, font, s10, Arial Gui, Add, Text,,Videos Gui, Add, Checkbox, vPFVid, Playfield Videos Gui, Add, Checkbox, vBGVid, Backglass Videos Gui, Add, Checkbox, vDMDVid, DMD Videos (Req 3 Monitor setup/FutureDMD) Gui, Add, Text,,`nImages Gui, Add, Checkbox, vPFImage, Playfield Image Gui, Add, Checkbox, vBGImage, Backglass Image Gui, Add, Checkbox, vDMDImage, DMD Image (Req 3 Monitor setup/FutureDMD) Gui, Add, Text,, `n Gui, Add, Button, Default gConfirm, Next Gui, Show WinWaitClose, Choose Media to Record ;Set the video recording time Gui, Show, W400 H260, Video Recording Time gui, font, s10, Arial Gui, Add, Text,,Select duration of video recordings:`n Gui, Add, Radio, vRadioGroup1, 5 seconds Gui, Add, Radio, vRadioGroup2, 15 seconds Gui, Add, Radio, vRadioGroup3, 30 seconds Gui, Add, Radio, Checked vRadioGroup4, 60 seconds Gui, Add, Radio, vRadioGroup5, 120 seconds Gui, Add, Radio, vRadioGroup6, 300 seconds Gui, Add, Text,, `n Gui, Add, Button, Default gSelect, Next Gui, Show WinWaitClose, Video Recording Time ;Recording Format Gui, Show, W500 H170, Recording Format gui, font, s10, Arial Gui, Add, Text,,Record all videos in:`n Gui, Add, Radio, checked vRadioGroupRF1, .f4v format Gui, Add, Radio, vRadioGroupRF2, .mp4 format Gui, Add, Text,, `n Gui, Add, Button, Default gMediaR, Next Gui, Show WinWaitClose, Recording Format ;File naming convention Gui, Show, W500 H170, Media Naming gui, font, s10, Arial Gui, Add, Text,,Media filenames should be based on:`n Gui, Add, Radio, checked vRadioGroupMF1, Description tag Example: Medieval Madness (Williams 1997).%RecExt% Gui, Add, Radio, vRadioGroupMF2, FP table filename Example: Medieval Madness ZED.%RecExt% Gui, Add, Text,, `n Gui, Add, Button, Default gMediaF, Next Gui, Show WinWaitClose, Media Naming ;******Save Settings***** FileDelete %A_ScriptDir%\PBXrecorderFP.ini FileAppend,%Version%`n%PinballXPath%`n%OnlyRecordMissingVideos%`n%PFVideoOnly%`n%BGVideoOnly%`n%DMDVideoOnly%`n%PFImageOnly%`n%BGImageOnly%`n%DMDImageOnly%`n%RecFormat%`n%RecTime%`n%MediaFileNaming%`n, %A_ScriptDir%\PBXrecorderFP.ini ;Display ini settings If (OnlyRecordMissingVideos = 2) TempStr2 := "`nFind and record missing media files only`n(Existing media files are kept)" Else If (OnlyRecordMissingVideos = 1) TempStr2 := "`nRecord complete media set for new and incomplete tables`n(Incomplete media sets are deleted/re-recorded)" Else If (OnlyRecordMissingVideos = 3) TempStr2 := "`nRecord complete media set for new tables only`n(If any media is found, the table is skipped. Tables with no media are recorded)" Else TempStr2 := "`nStart over and record complete media sets for all tables`n(All existing media is replaced)" If RecordingFormat = 1 RecExt=mp4 Else RecExt=f4v TempStr1 = `nMedia to Record (%RecTime% sec %RecExt% videos):`n If (PFVideoOnly=1) TempStr1 = %TempStr1%Playfield Videos`n If (BGVideoOnly=1) TempStr1 = %TempStr1%Backglass Videos`n If (DMDVideoOnly=1) TempStr1 = %TempStr1%DMD Videos`n If (PFImageOnly=1) TempStr1 = %TempStr1%Playfield Images`n If (BGImageOnly=1) TempStr1 = %TempStr1%Backglass Images`n If (DMDImageOnly=1) TempStr1 = %TempStr1%DMD Images`n If (MediaFileNaming=0) TempStr1 = %TempStr1%`nMedia filename based on Description tags`n Else TempStr1 = %TempStr1%`nMedia filename based on FP table filename`n Msgbox, 0, Current Recorder Settings, PinballX Path: %PinballXPath%`n%TempStr2%`n%TempStr1%`n(Wheel Image download support. See FTPLoginInfo.txt)`n`n`nPress ESC to abort script } FileAppend,`nPinballx.ini`n%Version%`n%PinballXPath%`n%OnlyRecordMissingVideos%`n%PFVideoOnly%`n%BGVideoOnly%`n%DMDVideoOnly%`n%PFImageOnly%`n%BGImageOnly%`n%DMDImageOnly%`n%RecFormat%`n%RecTime%`n%MediaFileNaming%`n`nIdentify all FP XML files...`n, %A_ScriptDir%\PBXrecorder.log ;Set FFMpeg, OBS and MediaOut folder locations OBSPath = C:\obs-studio FFMpegPath = %A_ScriptDir%\FFMpeg\bin MediaOutPath = %PinballXPath%\Media ;************************************************************************************************ ;************************************************************************************************ ;2. Time to walk find all the FP xml files ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ;Arrays for finding and storing FP xml files and path information XMLPathArray := Object() XMLFileNameArray := Object() WorkingPathArray := Object() TablePathArray := Object() ExecutableArray := Object() ;Array[j] := A_LoopField ; Array of xml search strings Array := ["[FuturePinball]", "Enabled=", "WorkingPath=", "TablePath=", "Executable=", "[System_", "Name=", "WorkingPath=", "TablePath=", "Executable=", "Enabled=", "SystemType=", "XXXX END XXXX"] ; 1 2 3 4 5 6 7 8 9 10 11 12 13 FPXMLCount=1 FPSearchIndex:=1 FPActiveFlag=0 FPKeepFlag = 1 ;Assume System is enabled FPSystemFlag = 0 FPFirstSystemDone = 0 If (DragAndDrop<>1) PauseTime:=200 Else PauseTime:=0 ;Open PinballX.ini file and identify FP xml files ;================================================= Loop, Read, %PinballXPath%\Config\PinballX.ini { ;****** Find 1st System ****** If (FPFirstSystemDone=0 and FPActiveFlag=0) ;Search for 1st System start { StringGetPos, Position, A_LoopReadLine, [FuturePinball] If Position = 0 { FPActiveFlag = 1 TempStr = %PinballXPath%\Databases\Future Pinball XMLPathArray[FPXMLCount] := TempStr XMLFileNameArray[FPXMLCount] := "Future Pinball" TempStr1 := XMLPathArray[FPXMLCount] TempStr2 := XMLFileNameArray[FPXMLCount] ;Msgbox, XMLPathArray[%FPXMLCount%]=%TempStr1%\%TempStr2% } else { continue ;Read next line } } else if (FPFirstSystemDone==0 and FPActiveFlag==1) ;Collect info for 1st system { StringGetPos, Position, A_LoopReadLine, WorkingPath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 13) WorkingPathArray[FPXMLCount] := TempStr1 TempStr2 := WorkingPathArray[FPXMLCount] ;Msgbox WorkingPathArray[%FPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Tablepath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 11) TablePathArray[FPXMLCount] := TempStr1 TempStr2 := TablePathArray[FPXMLCount] ;Msgbox TablePathArray[%FPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Executable If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 12) ExecutableArray[FPXMLCount] := TempStr1 TempStr2 := ExecutableArray[FPXMLCount] ;Msgbox ExecutableArray[%FPXMLCount%]=%TempStr2% } StringGetPos, Position, A_LoopReadLine, Enabled=True If Position = 0 { FPKeepFlag = 1 ;MsgBox, enabled is true } StringGetPos, Position, A_LoopReadLine, Enabled=False If Position = 0 { FPKeepFlag = 0 ;MsgBox, enabled is false } StringGetPos, Position, A_LoopReadLine, [ ;End of section found If Position = 0 { FPFirstSystemDone=1 StringGetPos, pos, A_LoopReadLine, [ if pos = 0 { If FPKeepFlag = 1 ;Keep System info { TempStr1 := XMLPathArray[FPXMLCount] TempStr2 := XMLFileNameArray[FPXMLCount] TempStr3 := WorkingPathArray[FPXMLCount] TempStr4 := TablePathArray[FPXMLCount] TempStr5 := ExecutableArray[FPXMLCount] ;Msgbox, XMLPathArray[%FPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%FPXMLCount%]=%TempStr3%`n TablePathArray[%FPXMLCount%]=%TempStr4%`n ExecutableArray[%FPXMLCount%]=%TempStr5% FileAppend, FP System #%FPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log FPXMLCount++ } Else { FileAppend, `nFuture Pinball System is disabled in the XML file`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%FPSystemFlag% %FPKeepFlag%) } FPActiveFlag = 0 FPKeepFlag = 1 ;Assume System is enabled } ; Need to check this line if it is the start of a new system StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { FPActiveFlag = 1 } } } ;****** Find Extra Systems ****** Else If (FPFirstSystemDone=1 and FPActiveFlag = 0) ;Search for start extra [System...] sections { StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { FPActiveFlag = 1 } else { continue ;Read next line } } else if (FPFirstSystemDone=1 and FPActiveFlag = 1) ;Collect info for the additional [System... sections { StringGetPos, Position, A_LoopReadLine, Name If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 6) TempStr = %PinballXPath%\Databases\%TempStr1% XMLPathArray[FPXMLCount] := TempStr XMLFileNameArray[FPXMLCount] := TempStr1 ;Msgbox, XMLPathArray[%FPXMLCount%]=%TempStr%\%TempStr1% } StringGetPos, Position, A_LoopReadLine, WorkingPath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 13) WorkingPathArray[FPXMLCount] := TempStr1 TempStr2 := WorkingPathArray[FPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, Tablepath If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 11) TablePathArray[FPXMLCount] := TempStr1 TempStr2 := TablePathArray[FPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, Executable If Position = 0 { TempStr1 := SubStr(A_LoopReadLine, 12) ExecutableArray[FPXMLCount] := TempStr1 TempStr2 := ExecutableArray[FPXMLCount] ;Msgbox %TempStr2% } StringGetPos, Position, A_LoopReadLine, SystemType=2 If Position = 0 { FPSystemFlag = 1 ;MsgBox, System is FP } StringGetPos, Position, A_LoopReadLine, Enabled=True If Position = 0 { FPKeepFlag = 1 ;MsgBox, System Enabled } StringGetPos, Position, A_LoopReadLine, Enabled=False If Position = 0 { FPKeepFlag = 0 ;MsgBox, System Disabled } StringGetPos, Position, A_LoopReadLine, [ If Position = 0 { If (FPSystemFlag = 1 and FPKeepFlag = 1) ;Keep System info { TempStr1 := XMLPathArray[FPXMLCount] TempStr2 := XMLFileNameArray[FPXMLCount] TempStr3 := WorkingPathArray[FPXMLCount] TempStr4 := TablePathArray[FPXMLCount] TempStr5 := ExecutableArray[FPXMLCount] ;Msgbox, XMLPathArray[%FPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%FPXMLCount%]=%TempStr3%`n TablePathArray[%FPXMLCount%]=%TempStr4%`n ExecutableArray[%FPXMLCount%]=%TempStr5% FileAppend, FP System #%FPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log FPXMLCount++ } Else { TempStr2 := XMLFileNameArray[FPXMLCount] FileAppend, Skipping this system: %TempStr2%.xml`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%FPSystemFlag% %FPKeepFlag%) } FPActiveFlag = 0 FPKeepFlag = 1 ;Assume System is enabled FPSystemFlag = 0 ; Need to check this line if it is the start of a new system StringGetPos, Position, A_LoopReadLine, [System_ If Position = 0 { FPActiveFlag = 1 } } } } ;End of file found, process last system found If (FPSystemFlag = 1 and FPKeepFlag = 1) ;Keep System info { TempStr1 := XMLPathArray[FPXMLCount] TempStr2 := XMLFileNameArray[FPXMLCount] TempStr3 := WorkingPathArray[FPXMLCount] TempStr4 := TablePathArray[FPXMLCount] TempStr5 := ExecutableArray[FPXMLCount] ;Msgbox, XMLPathArray[%FPXMLCount%]=%TempStr1%\%TempStr2%`n WorkingPathArray[%FPXMLCount%]=%TempStr3%`n TablePathArray[%FPXMLCount%]=%TempStr4%`n ExecutableArray[%FPXMLCount%]=%TempStr5% FileAppend, FP System #%FPXMLCount%:`n%TempStr1%\%TempStr2%.xml`n%TempStr3%`n%TempStr4%`n%TempStr5%`n`n, %A_ScriptDir%\PBXrecorder.log FPXMLCount++ } Else { TempStr2 := XMLFileNameArray[FPXMLCount] FileAppend, Skipping this system: %TempStr2%.xml`n`n, %A_ScriptDir%\PBXrecorder.log ;Msgbox, System Disabled (%FPSystemFlag% %FPKeepFlag%) } FPActiveFlag = 0 FPKeepFlag = 0 FPSystemFlag = 0 FPXMLCount-- FileAppend, Total number of FP systems found: %FPXMLCount%`n, %A_ScriptDir%\PBXrecorder.log If FPXMLCount = 0 { Msgbox No XML files were found. Check PinballX path. } ;************************************************************************************************ ;************************************************************************************************ ;3. If table selected via drag drop or right click, Allow user to add table to XML file ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ If (DragAndDrop=1) { Loop, %FPXMLCount% ;Search if table exists in XML files already { XMLPath:=XMLPathArray[A_Index] XMLFileName:=XMLFileNameArray[A_Index] WorkingPath:=WorkingPathArray[A_Index] TablePath:=TablePathArray[A_Index] Executable:=ExecutableArray[A_Index] FileAppend, `nAdding table to %XMLFileName%.xml (%A_Hour%:%A_Min%:%A_Sec%)`n`n, %A_ScriptDir%\PBXrecorder.log ;Open XML file and walk through every table ;========================== Loop, Read, %XMLPath%\%XMLFilename%.xml { IfInString, A_LoopReadLine, game name= { TableEnabled := 1 StringGetPos, start, A_LoopReadLine, = StringGetPos, end, A_LoopReadLine, > XTable := SubStr(A_LoopReadLine, start+3, end-start-3) ;----------------------------------------------------- ;Convert special chars in Table Name so they are used correctly ;----------------------------------------------------- ;Special handling for & in the Table Name. Change & to & IfInString, XTable, & { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+6) XTable = %TestTable%&%TestTable2% } ;Special handling for italian ' in the Table Name. Change ’ to ' IfInString, XTable, ’ { StringGetPos, start, XTable, ’ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+4) XTable = %TestTable%'%TestTable2% } ;Special handling for ™ in the Table Name. Change ™ to ™ IfInString, XTable, ™ { StringGetPos, start, XTable, ™ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+8) XTable = %TestTable%™%TestTable2% } If inStr(XTable, DragAndDropFileNameOnly) { XMLTableFound := 1 ;Table found in XML files, go ahead and record media break } } ;End of Else IfInString, A_LoopReadLine, /game } ;End of Loop, Read, %XMLPath%\%XMLFilename%.xml If (XMLTableFound=1) ;Table was found in XML files, go ahead and record media { break ;exit loop to record media } } ;End of Loop, %FPXMLCount% If (XMLTableFound<>1) ; XML table not found, so display XML dialog to add table to XML file { IPDBArray := Object() IPDBNameArray := Object() IPDBMfrArray := Object() IPDBYearArray := Object() IPDBTypeArray := Object() IPDBStart:=0 XMLAllStart:=0 XMLMatchFound:=0 Loop, %FPXMLCount% ;Create XML system list for the dialog { theXMLString2:=XMLPathArray[A_Index] SplitPath, theXMLString2,,,, theXMLString If (XMLAllStart = 0) ;Creating XML system list { XMLAllFPSysString=%theXMLString%| XMLAllStart := 1 } Else { XMLAllFPSysString = %XMLAllFPSysString%%theXMLString%| } ;Check if table path matches the current FP system path, if so mark xml system as default by adding extra | If (XMLMatchFound=0) { xmltpath:=TablePathArray[A_Index] If (xmltpath = DragAndDropFileDir) { XMLMatchFound:=1 XMLAllFPSysString = %XMLAllFPSysString%| ;also store executable for launch button LaunchExecutable:=ExecutableArray[A_Index] ;msgbox match%xmltpath% : %DragAndDropFileDir% } } } IfNotExist, %A_ScriptDir%\ipdb list.txt Msgbox, Please re-download PBX Recorder - ipdb list.txt file is missing Loop, Read, %A_ScriptDir%\ipdb list.txt ; Create the ipdb pinball table list for the dialog { StringSplit, TempWordArray, A_LoopReadLine,|, IPDBNameArray.Insert(TempWordArray1) ; Append this line to the array. IPDBMfrArray.Insert(TempWordArray4) ; Append this line to the array. IPDBYearArray.Insert(TempWordArray7) ; Append this line to the array. IPDBtypeArray.Insert(TempWordArray10) ; Append this line to the array. tempIPDB = %TempWordArray1% (%TempWordArray4% %TempWordArray7%) IPDBArray.Insert(tempIPDB) ; Append this line to the array. If (IPDBStart = 0) { allIPDBString = %tempIPDB% IPDBStart := 1 } Else allIPDBString = %allIPDBString%|%tempIPDB% } ; File drag and drop - store filename Loop %0% { GivenPath := %A_Index% Loop %GivenPath%, 1 DragAndDropFile = %A_LoopFileLongPath% DragAndDrop := 1 Break } SplitPath, DragAndDropFile,,,, DragAndDropFileNameOnly ;****** Display the XML Table entry dialog bpx ****** Gui, Font, S11 CDefault, Verdana Gui, Add, Text, x42 y22 w90 h20 +right , XML List Gui, Add, Text, x42 y52 w90 h20 +right, Game Gui, Add, Text, x42 y80 w90 h20 +right, Description Gui, Add, DropDownList, x142 y20 w280 h25 r10 altSubmit vXMLFPSystem, %XMLAllFPSysString% Gui, Add, Button, x442 y18 w100 h29 gXMLLaunch , Launch Gui, Add, Edit, x142 y50 w400 h25 vXMLTableFileName , %DragAndDropFileNameOnly% Gui, Add, Edit, x142 y80 w400 h20 vXMLDescText, Gui, Add, DropDownList, x146 y102 w396 h80 r10 sort altSubmit vXMLDescSelected gGetXMLDescSelected, %allIPDBString% ; IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, DB2S Found ; Else IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.exe ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, B2S.exe Found ; Else ; Gui, Add, Button, x22 y120 w70 h60 vXDB2S gXMLDB2S, DB2S Rename Gui, Add, Text, x142 y130 w220 h20 +center , Manufacturer Gui, Add, Text, x372 y130 w80 h20 +center , Year Gui, Add, Text, x462 y130 w80 h20 +center , Type Gui, Add, Edit, x142 y150 w220 h25 vXMLMfr, Gui, Add, Edit, x372 y150 w80 h25 vXMLYear, Gui, Add, Edit, x462 y150 w80 h25 vXMLType, Gui, Add, CheckBox, x142 y180 w120 h30 Checked vXMLEnabled, Table Enabled Gui, Add, CheckBox, x302 y180 w100 h30 Checked vXMLHideDMD, Hide DMD Gui, Add, CheckBox, x412 y180 w150 h30 Checked vXMLHideBG, Hide Backglass Gui, Add, DropDownList, x142 y215 w120 h25 r10 +center altSubmit vXMLAltExe, No Exe Tag||AlternateExe| Exe Gui, Add, Edit, x262 y216 w170 h25 vXMLAltExeName, Gui, Add, DropDownList, x442 y215 w100 h25 r10 +center altSubmit vXMLRating, No Rating||1 out of 5|2 out of 5|3 out of 5|4 out of 5|5 out of 5 Gui, Add, Button, x22 y280 w140 h30 gXMLCancel, Cancel Gui, Add, Button, x212 y280 w140 h30 gXMLSaveExit, Save && Exit Gui, Add, Button, x402 y280 w140 h30 gXMLSave, Save && Record GuiControl, Focus, XMLDescSelected Gui, Show, x127 y87 h327 w574,Add Table to XML - Start typing to perform Description auto-complete WinWaitClose, Add Table to XML - Start typing to perform Description auto-complete ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx } Else { MsgBox, 4,, Table exists in XML file already. Begin recording? (press Yes or No) IfMsgBox No ExitApp } } ;************************************************************************************************ ;************************************************************************************************ ;4. Time to walk through the tables and record videos ;************************************************************************************************ ;************************************************************************************************ ;************************************************************************************************ ; Disabling "Application has stopped Working" dialog ;(https://www.raymond.cc/blog/disable-program-has-stopped-working-error-dialog-in-windows-server-2008/) RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\Windows Error Reporting, DontShowUI, 0x00000001 Rectime := Rectime + 10 ;Pad record time by 10 seconds Loopcount:=0 Recordcount:=0 Loop, %FPXMLCount% { XMLPath:=XMLPathArray[A_Index] XMLFileName:=XMLFileNameArray[A_Index] WorkingPath:=WorkingPathArray[A_Index] TablePath:=TablePathArray[A_Index] Executable:=ExecutableArray[A_Index] FileAppend, `nWorking on %XMLFileName%.xml (%A_Hour%:%A_Min%:%A_Sec%)`n`n, %A_ScriptDir%\PBXrecorder.log ;Read FP Registry and FutureDMD Settings - may need to be even number values or it may not record ;======================= RegRead, PF_width, HKCU, Software\Future Pinball\GamePlayer, Width RegRead, PF_height, HKCU, Software\Future Pinball\GamePlayer, Height RegRead, BG_width, HKCU, Software\Future Pinball\GamePlayer, SecondMonitorWidth RegRead, BG_height, HKCU, Software\Future Pinball\GamePlayer, SecondMonitorHeight IniRead, DMD_width, %WorkingPath%\FutureDMD.ini, default, SizeW IniRead, DMD_height, %WorkingPath%\FutureDMD.ini, default, SizeH IniRead, DMD_X, %WorkingPath%\FutureDMD.ini, default, PosX IniRead, DMD_Y, %WorkingPath%\FutureDMD.ini, default, PosY ;Save FP Registry and FutureDMD Settings to PBX recorder log FileAppend, FP Registry and FutureDMD Settings`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %PF_width%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %PF_height%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %BG_width%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %BG_height%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %DMD_width%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %DMD_height%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %DMD_X%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, %DMD_Y%`n, %A_ScriptDir%\PBXrecorder.log ;OBS file check IfNotExist, %OBSPath%\bin\64bit\obs64.exe { FileAppend, `nWARNING: The file obs64.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file obs64.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file obs64.exe could not be found`n`n, %A_ScriptDir%\PBXrecorder.log } ;FFMPEG file check IfNotExist, %FFMpegPath%\ffmpeg.exe { FFMpegPath = %FFMpegPath%\bin IfNotExist, %FFMpegPath%\ffmpeg.exe FileAppend, `nWARNING: The file ffmpeg.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file ffmpeg.exe could not be found`n, %A_ScriptDir%\PBXrecorder.log FileAppend, WARNING: The file ffmpeg.exe could not be found`n`n, %A_ScriptDir%\PBXrecorder.log } ;Create Media directories if needed ;========================== MediaSubDir:=XMLFileName MediaSubDirOut:=XMLFileName If (BetaMode=1) { MediaSubDirOut = %MediaSubDirOut% Beta Msgbox, 0,, Beta Mode. All new media stored in %MediaOutPath%\%MediaSubDirOut%, 20 } FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Backglass Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Backglass Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\DMD Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\DMD Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Table Images FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Table Videos FileCreateDir, %MediaOutPath%\%MediaSubDirOut%\Wheel Images ;Start of new XML file if (DragAndDrop<>1) { Progress, x200 y200 zh0 M h200 w600 FS10, `n%WorkingPath%`n %TablePath%`n %Executable%`n`n`n(Press ESC anytime to abort script) , `nWorking on %XMLFileName%.xml, System XML #%A_Index% of %FPXMLCount% ... , Arial Sleep 2000 } ; Clean up ;========================== FileDelete, %A_ScriptDir%\playfield.mkv FileDelete, %A_ScriptDir%\bg.mkv FileDelete, %A_ScriptDir%\dmd.mkv Run, taskkill /T /IM obs64.exe ,,UseErrorLevel WinKill, Error Progress, Off ;*************** Screensize check - How good are the settings **************** ;========================== XDMD_X:=DMD_X-PF_width ;Reference to Top Left of Playfield screen SysGet, VirtualScreenWidth, 78 TotalScreenWidth := DMD_X + DMD_width DMD_oldwidth := DMD_Width PFBGWidth := PF_width+BG_width DMDScreenWidth := VirtualScreenWidth - PFBGWidth DMDScreenHeight := MonitorBottom DMDXCrop := DMD_X - PFBGWidth ;Convert all width and height to even values for best recording success PF_width := (floor(PF_width/2))*2 PF_height := (floor(PF_height/2))*2 BG_width := (floor(BG_width/2))*2 BG_height := (floor(BG_height/2))*2 DMD_width := (floor(DMD_width/2))*2 DMD_height := (floor(DMD_height/2))*2 FileAppend, `nValues used for media capture (height/width forced to even values)`n, %A_ScriptDir%\PBXrecorder.log FileAppend, VirtualScreenWidth = %VirtualScreenWidth%`n, %A_ScriptDir%\PBXrecorder.log FileAppend, TotalScreenWidth = %TotalScreenWidth% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, PF_width = %PF_width% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, PF_height = %PF_height% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, BG_width = %BG_width% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, BG_height = %BG_height% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_width = %DMD_width% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_height = %DMD_height% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_X_offset = %XDMD_X% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_Y_offset = %DMD_Y% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, -----------------------------------------`n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_tot_offset = %DMD_X% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMD_orig_width = %DMD_oldwidth% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMDScreenWidth = %DMDScreenWidth% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMDScreenHeight = %DMDScreenHeight% `n, %A_ScriptDir%\PBXrecorder.log FileAppend, DMDScreenX = %DMDXCrop% `n, %A_ScriptDir%\PBXrecorder.log ;PF width check If ((PF_width > VirtualScreenWidth) and (PFVideoOnly = 1 or PFImageOnly = 1)) { Msgbox, 0, FP Settings: Playfield size check, Warning: FP Playfield(%PF_width%) width exceeds the actual size of the windows desktop(%VirtualScreenWidth%). Review FP settings`n`nPlayfield recording may not work, 60 FileAppend, WARNING: FP Settings Playfield width exceeds the actual size of windows desktop. Review FP settings`n, %A_ScriptDir%\PBXrecorder.log } ;PF and BG width check If ((PFBGWidth > VirtualScreenWidth) and (BGVideoOnly = 1 or BGImageOnly = 1)) { Msgbox, 0, FP Settings: Backglass size check, Warning: FP Playfield(%PF_width%) plus Backglass(%BG_width%) width exceeds the actual size of windows desktop (%VirtualScreenWidth%). Review FP settings`n`nBackglass recording may not work, 60 FileAppend, WARNING: FP Settings Playfield(%PF_width%) plus Backglass(%BG_width%) width exceeds the actual size of windows desktop (%VirtualScreenWidth%). Review FP settings`n, %A_ScriptDir%\PBXrecorder.log } ;PF and BG and DMD width check If ((TotalScreenWidth > VirtualScreenWidth) and (DMDVideoOnly = 1 or DMDImageOnly = 1)) { DMD_Width := (floor((DMD_oldwidth - (TotalScreenWidth - VirtualScreenWidth))/2))*2 Msgbox, 0, FutureDMD: DMD size check, Warning: FutureDMD width/offset is not correct`nReducing DMD width from %DMD_oldwidth% to %DMD_width%. Review FutureDMD.ini settings`n`nDMD recording may not work, 60 FileAppend, WARNING: DMD window settings incorrect - auto-resizing (%DMD_oldwidth% to %DMD_width%). Review FutureDMD settings`n, %A_ScriptDir%\PBXrecorder.log } ;Write modified settings to OBS config files IniWrite, %PF_width%, %OBSPath%\config\obs-studio\basic\profiles\playfield\basic.ini, Video, OutputCX IniWrite, %PF_height%, %OBSPath%\config\obs-studio\basic\profiles\playfield\basic.ini, Video, OutputCY IniWrite, %A_ScriptDir%, %OBSPath%\config\obs-studio\basic\profiles\playfield\basic.ini, AdvOut, RecFilePath IniWrite, %BG_width%, %OBSPath%\config\obs-studio\basic\profiles\bg\basic.ini, Video, OutputCX IniWrite, %BG_height%, %OBSPath%\config\obs-studio\basic\profiles\bg\basic.ini, Video, OutputCY IniWrite, %A_ScriptDir%, %OBSPath%\config\obs-studio\basic\profiles\bg\basic.ini, AdvOut, RecFilePath IniWrite, %DMDScreenWidth%, %OBSPath%\config\obs-studio\basic\profiles\dmd\basic.ini, Video, OutputCX IniWrite, %DMDScreenHeight%, %OBSPath%\config\obs-studio\basic\profiles\dmd\basic.ini, Video, OutputCY IniWrite, %A_ScriptDir%, %OBSPath%\config\obs-studio\basic\profiles\dmd\basic.ini, AdvOut, RecFilePath ;Open XML file and walk through every table ;========================== ExecutableBackup:=Executable PrintFFMPEGExamples:=1 Loop, Read, %XMLPath%\%XMLFilename%.xml { IfInString, A_LoopReadLine, game name= { TableEnabled := 1 Executable:=ExecutableBackup StringGetPos, start, A_LoopReadLine, = StringGetPos, end, A_LoopReadLine, > XTable := SubStr(A_LoopReadLine, start+3, end-start-3) ;Msgbox, what%XTable%`n%A_LoopReadLine%`n%start%`n%end% ;----------------------------------------------------- ;Convert special chars in Table Name so they are used correctly ;----------------------------------------------------- ;Special handling for ® in the Table Name. Change ® to ® IfInString, XTable, ® { StringGetPos, start, XTable, ® TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+2) XTable = %TestTable%%TestTable2% ;msgbox %XTable% } ;Special handling for & in the Table Name. Change & to & IfInString, XTable, & { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+6) XTable = %TestTable%&%TestTable2% } ;Special handling for Italian ® in the Table Name. Change ® to ® IfInString, XTable, ® { StringGetPos, start, XTable, & TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+7) XTable = %TestTable%�%TestTable2% } ;Special handling for italian ' in the Table Name. Change ’ to ' IfInString, XTable, ’ { StringGetPos, start, XTable, ’ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+4) XTable = %TestTable%'%TestTable2% } ;Special handling for ™ in the Table Name. Change ™ to ™ IfInString, XTable, ™ { StringGetPos, start, XTable, ™ TestTable := SubStr(XTable, 1, start) TestTable2 := SubStr(XTable, start+8) XTable = %TestTable%™%TestTable2% } ;Identify if fpt IfExist, %TablePath%\%Xtable%.fpt { Table = %XTable%.fpt TableExists := 1 } ;Else IfExist, %TablePath%\%Xtable%.vpx ;{ ; Table = %XTable%.vpx ; TableExists := 1 ;} Else ;must be vpx file { ;Table = %XTable%.vpx TableExists := 0 } } Else IfInString, A_LoopReadLine, /description { StringGetPos, start, A_LoopReadLine, <description> StringGetPos, end, A_LoopReadLine, </description> Description := SubStr(A_LoopReadLine, start+14, end-start-13) ;---------------------------------------------------- ;Remove invalid chars from Description name like : / \ * ? " < > | ;---------------------------------------------------- IfInString, Description, : { StringGetPos, start, Description, : TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, / { StringGetPos, start, Description, / TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, \ { StringGetPos, start, Description, \ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, * { StringGetPos, start, Description, * TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, * { StringGetPos, start, Description, * TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+6) Description = %TestTable%%TestTable2% } IfInString, Description, ? { StringGetPos, start, Description, ? TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, " { StringGetPos, start, Description, " TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, < { StringGetPos, start, Description, < TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, > { StringGetPos, start, Description, > TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } IfInString, Description, | { StringGetPos, start, Description, | TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } ;----------------------------------------------------- ;Convert special chars in Description so they are used correctly ;----------------------------------------------------- ;Special handling for ® in the Description. Change ® to ® IfInString, Description, ® { StringGetPos, start, Description, ® TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+2) Description = %TestTable%%TestTable2% } ;Special handling for & in the Description. Change & to & IfInString, Description, & { StringGetPos, start, Description, & TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+6) Description = %TestTable%&%TestTable2% } ;Special handling for ® in the Description. Change ® to ® IfInString, Description, ® { StringGetPos, start, Description, ® TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+7) Description = %TestTable%�%TestTable2% } ;Special handling for italian ' in the Description. Change ’ to ' IfInString, Description, ’ { StringGetPos, start, Description, ’ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+4) Description = %TestTable%'%TestTable2% } ;Special handling for ™ in the Description. Change ™ to ™ IfInString, Description, ™ { StringGetPos, start, Description, ™ TestTable := SubStr(Description, 1, start) TestTable2 := SubStr(Description, start+8) Description = %TestTable%™%TestTable2% } FileAppend, `n%Description%`n, %A_ScriptDir%\PBXrecorder.log If TableExists = 0 FileAppend, Table file not found: %TablePath%\%XTable%.fpt`n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, /alternateExe { StringGetPos, start, A_LoopReadLine, <alternateExe> StringGetPos, end, A_LoopReadLine, </alternateExe> Executable := SubStr(A_LoopReadLine, start+15, end-start-14) ;Msgbox, %Executable% FileAppend, AlternateExe found in xml: %Executable%`n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, /exe { StringGetPos, start, A_LoopReadLine, <exe> StringGetPos, end, A_LoopReadLine, </exe> Executable := SubStr(A_LoopReadLine, start+6, end-start-5) ;Msgbox, %Executable% FileAppend, Exe found in xml: %Executable%`n, %A_ScriptDir%\PBXrecorder.log } Else IfInString, A_LoopReadLine, enabled>False { ;Msgbox, %A_LoopReadLine% FileAppend, Table disabled in xml: %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log TableEnabled := 0 } Else IfInString, A_LoopReadLine, enabled>True { ;Msgbox, %A_LoopReadLine% TableEnabled := 1 } Else IfInString, A_LoopReadLine, /game { If TableEnabled = 1 { If TableExists = 1 { Loopcount:=Loopcount + 1 ;Msgbox, recording ;Check if Media Files exist and skip if skip is enabled ;=================================================== MediaFoundFlag:=0 If (MediaFileNaming=0) SearchString:=Description Else SearchString:=Xtable If (PrintFFMPEGExamples=1) { PrintFFMPEGExamples:=0 FileAppend, `nEXAMPLE of all ffmpeg.exe commands used`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vf "rotate=PI:bilinear=0" "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t 1 -f gdigrab -framerate 1 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size %PF_width%x%PF_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %PF_width% -offset_y 0 -video_size %BG_width%x%BG_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log ; FileAppend, "%FFMpegPath%\ffmpeg" -y -t %RecTime% -rtbufsize 1500M -f gdigrab -framerate 30 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_Height% -i desktop -vcodec libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\playfield.mkv" -ss 10 -to 1000 -vf [in]rotate=PI:bilinear=0[middle];[middle]scale=1920:-1[out] -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\bg.mkv" -ss 10 -to 1000 -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log FileAppend, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\dmd.mkv" -ss 10 -to 1000 -vf "crop=w=%DMD_width%:h=%DMD_height%:x=%DMDXCrop%:y=%DMD_Y%" -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%"`n`n, %A_ScriptDir%\PBXrecorder.log } If ((OnlyRecordMissingVideos = 1) or (OnlyRecordMissingVideos = 2) or (OnlyRecordMissingVideos = 3)) { ;Perform media check for missing files MediaFoundFlag:=1 MediaAtLeastOneFound:=0 If (PFVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Videos\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: Table Video`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (BGVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Videos\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: BackGlass Video`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (DMDVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Videos\%SearchString%.* { FileAppend, MISSING: DMD Video`n, %A_ScriptDir%\PBXrecorder.log If DMD_width > 0 { MediaFoundFlag:=0 } } Else { MediaAtLeastOneFound:=1 } } If (PFImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Images\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: Table Image`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (BGImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Images\%SearchString%.* { MediaFoundFlag:=0 FileAppend, MISSING: BackGlass Image`n, %A_ScriptDir%\PBXrecorder.log } Else { MediaAtLeastOneFound:=1 } } If (DMDImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Images\%SearchString%.* { FileAppend, MISSING: DMD Image`n, %A_ScriptDir%\PBXrecorder.log If DMD_width > 0 { MediaFoundFlag:=0 } } Else { MediaAtLeastOneFound:=1 } } } ;end of If ((OnlyRecordMissingVideos = 1) or (OnlyRecordMissingVideos = 2) or (OnlyRecordMissingVideos = 3)) Else { FileAppend, PBXrecorder set to record complete media set`n, %A_ScriptDir%\PBXrecorder.log } ;=========================================================================== ; Extra FP file checks - Wheel images (FTP download supported) ;=========================================================================== ;Print out message to log file if DirectB2s file is missing ;IfNotExist, %TablePath%\%XTable%.directb2s ;{ ; IfNotExist, %TablePath%\%XTable%.exe ; { ; FileAppend, FYI: No DirectB2S/B2S.exe File. %TablePath%\%XTable%.directb2s`n, %A_ScriptDir%\PBXrecorder.log ; } ; Else ; { ; FileAppend, FYI: No DirectB2S but B2S was found. %TablePath%\%XTable%.directb2s`n, %A_ScriptDir%\PBXrecorder.log ; } ;} ;Print out message to log file if Wheel image is missing - Perform FTP IfNotExist, %MediaOutPath%\%MediaSubDir%\Wheel Images\%SearchString%.png { ;============================================================= ; Download Wheel from PinballX FTP if user has filled in FTP login info ;============================================================= IfExist, %A_ScriptDir%\FTPLoginInfo.txt { FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 2 IfNotInString, tempStr, USERNAME { Progress, x200 y200 zh0 M h200 w600 FS10, `n`Wheel Image missing... Check PinballX FTP site`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Attempting PinballX FTP download , Arial ;Strip out the {...} from the description if found StringSplit, SearchStringArray, Description, {} ;drop the 2nd part SearchStringArray1:=Trim(SearchStringArray1) SearchStringArray3:=Trim(SearchStringArray3) If (StrLen(SearchStringArray3)>0) SearchStringArray1=%SearchStringArray1% %SearchStringArray3% FileToGet = %SearchStringArray1%.png FileDelete %A_ScriptDir%\FTPtemp.bat FileAppend, open online.gameex.com`n, %A_ScriptDir%\FTPtemp.bat FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 2 FileAppend, %tempStr%`n, %A_ScriptDir%\FTPtemp.bat FileReadLine, tempStr, %A_ScriptDir%\FTPLoginInfo.txt, 3 FileAppend, %tempStr%`n, %A_ScriptDir%\FTPtemp.bat FileAppend, ( binary hash cd "/-PinballX-/Media/Future Pinball/Wheel Images" get "%FileToGet%" bye ), %A_ScriptDir%\FTPtemp.bat RunWait %comspec% /c ftp.exe -s:"%A_ScriptDir%\FTPtemp.bat" FileDelete %A_ScriptDir%\FTPtemp.bat FileMove %A_ScriptDir%\%FileToGet%, %MediaOutPath%\%MediaSubDirOut%\Wheel Images\%Description%.png, 1 IfNotExist, %MediaOutPath%\%MediaSubDirOut%\Wheel Images\%Description%.png { FileAppend, FYI (Wheel not found in FTP): No Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } Else { FileAppend, Downloaded via FTP: Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, FYI (FTP not enabled): No Wheel Image - %Description%.png`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, FYI (FTP not enabled): No Wheel Image - %SearchString%.png`n, %A_ScriptDir%\PBXrecorder.log } } ; END OF Extra FP file checks - Wheel images (FTP download supported) ;=========================================================================== ; Media checked - Decide whether to record or skip table ;=========================================================================== IfEqual MediaFoundFlag, 1 ;If all media exists then skip table { If PauseTime>=10 PauseTime:=PauseTime-5 TempLongPath = %TablePath%\%Table% if (DragAndDrop<>1) { Progress, x200 y200 zh0 M h200 w600 FS10, `nMedia already exists. Skipping...`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Capturing Videos... #%Loopcount% , Arial Sleep %PauseTime% FileAppend, Skipping table... %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } Else If inStr(TempLongPath, DragAndDropFile) ;Check if drag and drop table already has media { DragAndDropTableFound := -1 Progress, x200 y200 zh0 M h200 w600 FS10, `nDrag and Drop table media already exists. Skipping...`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Drag and Drop... #%Loopcount% , Arial Sleep 3000 FileAppend, Drag and drop table already has Media. Skipping... %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } continue ;Skipping table!!! } Else If (DragAndDrop=1) ;and MediaFoundFlag = 0 ;Handle Drag and drop table recording { ;Check if current table matches the drag and drop table TempLongPath = %TablePath%\%Table% If inStr(TempLongPath, DragAndDropFile) ;Match - go ahead and record { DragAndDropTableFound := 1 Progress, x200 y200 M h240 w600 FS10 CB0000FF, `n`nLoading "%Table%"`n`nDrag and Drop recording will start in %LoadTime% seconds...`n(Press PAUSE if you need to edit/setup table)`n(Press ESC anytime to abort script) ,`n`n%Description%`n, Capturing Videos... #%Loopcount% , Arial FileAppend, Launching table: %Executable% /STAYINRAM /open %TablePath%\%Table% /play /exit`n, %A_ScriptDir%\PBXrecorder.log } Else ;No match - skip this table { FileAppend, Skipping table due to Drag and Drop mode... %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log continue ;Skipping table } } Else If ((OnlyRecordMissingVideos=3) and (MediaAtLeastOneFound=1)) ;check if Mode = Record ONLY new tables(Ignore partial media set) AND any if media was found { FileAppend, Skipping table - Recording only new tables. Partial media set exists... %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log continue ;Skipping table } Else ;MediaFoundFlag = 0 ;Launch table to record { Progress, x200 y200 M h240 w600 FS10 CB0000FF, `n`nLoading "%Table%"`n`nRecording will start in %LoadTime% seconds...`n(Press PAUSE if you need to edit/setup table)`n(Press ESC anytime to abort script) ,`n`n%Description%`n, Capturing Videos... #%Loopcount% , Arial FileAppend, Launching table: %Executable% /STAYINRAM /open %TablePath%\%Table% /play /exit`n, %A_ScriptDir%\PBXrecorder.log } ;================================================= ;Start Table ;================================================= Recordcount:=Recordcount + 1 WinHide, ahk_class Button WinHide, ahk_class Shell_TrayWnd Run, "%WorkingPath%\%Executable%" /STAYINRAM /open "%TablePath%\%Table%" /play /exit LoadingTable:=1 Process, wait, Future Pinball.exe If DMD_width > 0 Run, %WorkingPath%\FutureDMD.exe table="%Table%" close=1 WinWaitActive, ahk_class FuturePinballOpenGL If (TestMode=1) ;debug speed up of recording { Loop, 50 ;DEBUG { j := A_Index/1.0 Progress,%j% Sleep 100 If (PBXRPauseMode=1) { Goto, PBRXPaused } } ; Allow time for table score display to get well beyond loading and boot images } Else { Loop, % LoadTimeX ; { j := A_Index/LoadTimeX*100 Progress,%j% Sleep 100 If (PBXRPauseMode=1) { Goto, PBRXPaused } } ; Allow time for table score display to get well beyond loading and boot images } Progress, Off LoadingTable:=0 PBRXPaused: If (LoadingTable=1) ;User has paused PBX Recorder { Progress, Off WindowX:=PF_width/2 -200 Progress, x%WindowX% y0 h25 w400 FS10 CB0000FF, Paused. Press Pause key to start recording , Paused. Press Pause key to start recording, Press Pause to Resume , Arial WinWaitClose, Press Pause to Resume } LoadingTable:=0 PBXRPauseMode:=0 ; Record Video as .mkv - Fast Capture and take screenshots ;============================================================ FileAppend, Video and screenshot capture (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log If (OnlyRecordMissingVideos = 2) ;Mode = RECORD MISSING MEDIA ONLY ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { If (PFImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Images\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection playfield --profile playfield --scene playfield --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } If (BGImageOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Images\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection bg --profile bg --scene bg --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } If (DMDImageOnly=1) { If DMD_width > 0 { IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Images\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection dmd --profile dmd --scene dmd --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, Screenshot skipped (Bad DMD size) "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } ; Sleep,3000 If (PFVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\Table Videos\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection playfield --profile playfield --scene playfield --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\playfield\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } If (BGVideoOnly=1) { IfNotExist, %MediaOutPath%\%MediaSubDir%\BackGlass Videos\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection bg --profile bg --scene bg --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } If (DMDVideoOnly=1) { If DMD_width > 0 { IfNotExist, %MediaOutPath%\%MediaSubDir%\DMD Videos\%SearchString%.* { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection dmd --profile dmd --scene dmd --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } Else { FileAppend, Recording skipped (Bad DMD size) "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } } Else If ((OnlyRecordMissingVideos=3) and (MediaAtLeastOneFound=1)) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { ;Safety check for Mode = Record only new tables (Ignore partial media set). FileAppend, Skipping table - XXX Recording only new tables. Partial media set exists... %TablePath%\%Table%`n, %A_ScriptDir%\PBXrecorder.log } Else ;Record everything for this table (Mode = Re-record all, Record if incomplete table, Record if new table) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { If (PFImageOnly=1) { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection playfield --profile playfield --scene playfield --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } If (BGImageOnly=1) { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection bg --profile bg --scene bg --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } If (DMDImageOnly=1) { If DMD_width > 0 { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection dmd --profile dmd --scene dmd --startrecording && exit,, Hide FileAppend, Screenshot "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } Else { FileAppend, Screenshot skipped (Bad DMD size) "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png"`n, %A_ScriptDir%\PBXrecorder.log } } ; Sleep,3000 If (PFVideoOnly=1) { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection playfield --profile playfield --scene playfield --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\playfield\playfield.mkv"`n, %A_ScriptDir%\PBXrecorder.log } If (BGVideoOnly=1) { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection bg --profile bg --scene bg --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\bg.mkv"`n, %A_ScriptDir%\PBXrecorder.log } If (DMDVideoOnly=1) { If DMD_width > 0 { RunWait, %comspec% /k cd "%OBSPath%\bin\64bit" && start obs64.exe --portable --collection dmd --profile dmd --scene dmd --startrecording && exit,, Hide FileAppend, Recording "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log } Else { FileAppend, Recording skipped (Bad DMD size) "%A_ScriptDir%\dmd.mkv"`n, %A_ScriptDir%\PBXrecorder.log } } } WinHide, ahk_class FuturePinball WinMinimize, ahk_class FuturePinball WinActivate, ahk_class FuturePinballOpenGL WinWaitActive, ahk_class FuturePinballOpenGL ;Timer if capturing any videos If (PFVideoOnly=1 OR BGVideoOnly=1 OR DMDVideoOnly=1) { OBSRecTime:=RecTime * 1000 Sleep,%OBSRecTime% } Else Sleep,3000 ; Clean up ;========================== Send ^{U down}^{U up} WinClose, ahk_class Qt5QWindowIcon Send {Enter} WinClose, ahk_class Qt5QWindowIcon Send {Enter} WinClose, ahk_class Qt5QWindowIcon Send {Enter} Run, taskkill /T /IM obs64.exe ,,UseErrorLevel WinHide, ahk_class FuturePinball WinMinimize, ahk_class FuturePinball WinActivate, ahk_class FuturePinballOpenGL WinWaitActive, ahk_class FuturePinballOpenGL Send {Esc} WinWaitClose, ahk_class FuturePinballOpenGL Process, close, FutureDMD.exe WinClose, ahk_class FuturePinball Run, taskkill /T /IM "Future Pinball.exe" ,,UseErrorLevel Run, taskkill /T /IM "FutureDMD.exe" ,,UseErrorLevel Run, taskkill /IM obs64.exe /F,,UseErrorLevel Sleep,5000 Run, taskkill /F /IM "Future Pinball.exe",,UseErrorLevel WinKill, Error WinShow, ahk_class Button WinShow, ahk_class Shell_TrayWnd ;PIN2DMD related - Not ready for primetime yet ;========================== ;IfExist, %A_ScriptDir%\pin2dmd\pin2dmd.exe ;{ ; Run, %A_ScriptDir%\pin2dmd\Pin2DMD.exe /r,,UseErrorLevel ;} ;IfExist, %A_ScriptDir%\pin2dmd\blank.ppm ;{ ; Run, %A_ScriptDir%\pin2dmd\Pin2DMD.exe /i %A_ScriptDir%\pin2dmd\blank.ppm,,UseErrorLevel ;} ;Convert Videos to .f4v/.mp4 if any mkv exist - Post Capture Trim and Transcode ;============================================================================ Progress, x200 y200 zh0 M h200 w600 FS10, `n`nConvert Videos to %RecExt% if video was captured`n`n(Press ESC anytime to abort script) ,`n`n%Description%, Capturing Videos... #%Loopcount% , Arial ConvertStatusStr= ( If (PFVideoOnly=1) ConvertStatusStr= %ConvertStatusStr% PF If (BGVideoOnly=1) ConvertStatusStr= %ConvertStatusStr% BG If (DMDVideoOnly=1) ConvertStatusStr= %ConvertStatusStr% DMD ConvertStatusStr= %ConvertStatusStr% ) FileAppend, Convert Videos to %RecExt% if video was captured (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log IfExist, %A_ScriptDir%\playfield.mkv ;If (PFVideoOnly=1) OR (PFImageOnly=1); { If (PFImageOnly=1) Run, "%FFMpegPath%\ffmpeg" -y -ss 1 -i "%A_ScriptDir%\playfield.mkv" -vframes 1 -vf "rotate=PI:bilinear=0" "%MediaOutPath%\%MediaSubDirOut%\Table Images\%SearchString%.png" Else { Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\playfield.mkv" -ss 10 -to 1000 -vf [in]rotate=PI:bilinear=0[middle];[middle]scale=1920:-1[out] -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%" FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\Table Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log } } IfExist, %A_ScriptDir%\bg.mkv ;If (BGVideoOnly=1) OR (BGImageOnly=1); { If (BGImageOnly=1) Run, "%FFMpegPath%\ffmpeg" -y -ss 1 -i "%A_ScriptDir%\bg.mkv" -vframes 1 "%MediaOutPath%\%MediaSubDirOut%\Backglass Images\%SearchString%.png" Else { Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\bg.mkv" -ss 10 -to 1000 -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%" FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\Backglass Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log } } IfExist, %A_ScriptDir%\dmd.mkv ;If (DMDVideoOnly=1) OR (DMDImageOnly=1); { If (DMDImageOnly=1) Run, "%FFMpegPath%\ffmpeg" -y -ss 1 -i "%A_ScriptDir%\dmd.mkv" -vframes 1 -vf "crop=w=%DMD_width%:h=%DMD_height%:x=%DMDXCrop%:y=%DMD_Y%" "%MediaOutPath%\%MediaSubDirOut%\DMD Images\%SearchString%.png" Else { Run, "%FFMpegPath%\ffmpeg" -y -i "%A_ScriptDir%\dmd.mkv" -ss 10 -to 1000 -vf "crop=w=%DMD_width%:h=%DMD_height%:x=%DMDXCrop%:y=%DMD_Y%" -map 0:0 -c:v libx264 -crf 26 "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%" FileAppend, Converting to "%MediaOutPath%\%MediaSubDirOut%\DMD Videos\%SearchString%.%RecExt%"`n, %A_ScriptDir%\PBXrecorder.log } } ; Clean up ;========================== Process, WaitClose, ffmpeg.exe, 500 Run, taskkill /IM ffmpeg.exe /F Run, taskkill /IM ffmpeg.exe /F Run, taskkill /IM ffmpeg.exe /F Progress, Off Sleep,3000 ;SoundBeep, 400, 200 FileDelete, %A_ScriptDir%\playfield.mkv FileDelete, %A_ScriptDir%\bg.mkv FileDelete, %A_ScriptDir%\dmd.mkv FileAppend, Table done (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log } ;End of If TableExists = 1 } ;End of If TableEnabled = 1 } ;End of Else IfInString, A_LoopReadLine, /game } ;End of Loop, Read, %XMLPath%\%XMLFilename%.xml } ; All done! ;=============== Progress, Off If (DragAndDrop<>1) { FileAppend, `n%Recordcount% new recordings out of %Loopcount% tables. Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Recording Finished,Recording is complete. %Recordcount% new recordings out of %Loopcount% tables } Else ;Drag and drop done { If (DragAndDropTableFound=1) { FileAppend, `nDrag and Drop recording finished (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, Recording is complete`n`n(%DragAndDropFile%). } Else If (DragAndDropTableFound=-1) { FileAppend, `nDrag and Drop skipped. Media already exists (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, No Recording. Media already exists`n`n(%DragAndDropFile%). } Else { FileAppend, `nDrag and Drop table was not found in the FP XML files (%DragAndDropFile%). Finished (%A_Hour%:%A_Min%:%A_Sec%)`n, %A_ScriptDir%\PBXrecorder.log Msgbox,0, Drag and Drop, Table was not found in the FP XML files. No recording performed`n`n(%DragAndDropFile%). } } ExitApp ;******************************************* ;******************************************* ; Misc Subroutines for Msgbox and Gui windows and Exit ;******************************************* ;******************************************* RecordModeButtonNames: IfWinNotExist, Record Mode return ; Keep waiting. SetTimer, RecordModeButtonNames, off WinActivate ControlSetText, Button1, &Videos Only ControlSetText, Button2, &Both return MissingVideosButtonNames: IfWinNotExist, Record Mode return ; Keep waiting. SetTimer, MissingVideosButtonNames, off WinActivate ControlSetText, Button1, &Missing Only ControlSetText, Button2, &All Tables return CurrSettingsButtonNames: IfWinNotExist, Current Recorder Settings return ; Keep waiting. SetTimer, CurrSettingsButtonNames, off WinActivate ControlSetText, Button1, &Continue ControlSetText, Button2, &Change return StoreMediaButtonNames: IfWinNotExist, Storing Media return ; Keep waiting. SetTimer, StoreMediaButtonNames, off WinActivate ControlSetText, Button1, &Combined ControlSetText, Button2, &Separate return GuiClose: ExitApp ;Pressing the ESC key will abort the script Esc:: IfWinNotExist,Add Table to XML IfWinNotExist,Press Pause to Resume { WinShow, ahk_class Button WinShow, ahk_class Shell_TrayWnd ExitApp } Else Return ; XML dialog present, do not exit Pause:: If (LoadingTable=1) { If (PBXRPauseMode=0) { PBXRPauseMode:=1 } Else { Progress, Off } } Return Confirm: Gui, Submit PFVideoOnly=0 BGVideoOnly=0 DMDVideoOnly=0 PFImageOnly=0 BGImageOnly=0 DMDImageOnly=0 if (PFVid = 1) PFVideoOnly=1 if (BGVid = 1) BGVideoOnly=1 if (DMDVid = 1) DMDVideoOnly=1 if (PFImage = 1) PFImageOnly=1 if (BGImage = 1) BGImageOnly=1 if (DMDImage = 1) DMDImageOnly=1 Gui, Destroy return Select: Gui, Submit if (RadioGroup1) RecTime:=5 else if (RadioGroup2) RecTime:=15 else if (RadioGroup3) RecTime:=30 else if (RadioGroup4) RecTime:=60 else if (RadioGroup5) RecTime:=120 else if (RadioGroup6) RecTime:=300 Gui, Destroy Return MediaMode: Gui, Submit if (MRadioGroup1) OnlyRecordMissingVideos:=2 else if (MRadioGroup2) OnlyRecordMissingVideos:=1 else if (MRadioGroup3) OnlyRecordMissingVideos:=0 else if (MRadioGroup4) OnlyRecordMissingVideos:=3 Gui, Destroy Return MediaF: Gui, Submit if (RadioGroupMF1) MediaFileNaming:=0 else if (RadioGroupMF2) MediaFileNaming:=1 Gui, Destroy Return MediaR: Gui, Submit if (RadioGroupRF1) { RecFormat:=0 RecExt=f4v } else if (RadioGroupRF2) { RecFormat:=1 RecExt=mp4 } Gui, Destroy Return ; Subroutines for Add Table to XML files GetXMLDescSelected: GuiControlGet, XMLDescSelected x:=IPDBArray[XMLDescSelected] GuiControl,, XMLDescText,%x% x:=IPDBMfrArray[XMLDescSelected] GuiControl,, XMLMfr,%x% x:=IPDBYearArray[XMLDescSelected] GuiControl,, XMLYear,%x% x:=IPDBTypeArray[XMLDescSelected] GuiControl,, XMLType,%x% Return XMLLaunch: GuiControlGet, XMLAltExe GuiControlGet, XMLAltExeName If (XMLAltExe = 1) IfExist, %WorkingPath%\%LaunchExecutable% { Run, "%WorkingPath%\%LaunchExecutable%" /STAYINRAM /open "%DragAndDropFile%" /play /exit } Else { Msgbox, %WorkingPath%\%LaunchExecutable% could not be found Return } Else IfExist, %WorkingPath%\%XMLAltExeName% Run, "%WorkingPath%\%XMLAltExeName%" /STAYINRAM /open "%DragAndDropFile%" /play /exit Else { Msgbox, %WorkingPath%\%XMLAltExeName% could not be found Return } Return XMLCancel: Gui, Destroy ExitApp XMLSaveExit: gosub XMLSave ;Msgbox XML Saved ExitApp XMLSave: ;Figure out which XML file to update GuiControlGet, XMLFPSystem tempXMLString1:=XMLPathArray[XMLFPSystem] tempXMLString2:=XMLFileNameArray[XMLFPSystem] tempXMLStringOrig=%tempXMLString1%\%tempXMLString2%.xml tempXMLStringBak=%tempXMLString1%\%tempXMLString2%.bak ;FileAppend, `t TEST %tempXMLStringOrig%`n, %A_ScriptDir%\XMLtest.txt FileCopy, %tempXMLStringOrig%, %tempXMLStringBak%, 1 FileRead, tempXMLfilestring, %tempXMLStringOrig% StringReplace, tempXMLfilestring, tempXMLfilestring, `r`n</menu> StringReplace, tempXMLfilestring, tempXMLfilestring, `n</menu> FileDelete, %tempXMLStringOrig% FileAppend, %tempXMLfilestring%, %tempXMLStringOrig% GuiControlGet, XMLTableFileName FileAppend, `t<game name="%XMLTableFileName%">`n, %tempXMLStringOrig% GuiControlGet, XMLDescText FileAppend, `t`t<description>%XMLDescText%</description>`n, %tempXMLStringOrig% FileAppend, `t`t<rom></rom>`n, %tempXMLStringOrig% GuiControlGet, XMLMfr FileAppend, `t`t<manufacturer>%XMLMfr%</manufacturer>`n, %tempXMLStringOrig% GuiControlGet, XMLYear FileAppend, `t`t<year>%XMLYear%</year>`n, %tempXMLStringOrig% GuiControlGet, XMLType FileAppend, `t`t<type>%XMLType%</type>`n, %tempXMLStringOrig% GuiControlGet, XMLHideDMD If (XMLHideDMD=1) FileAppend, `t`t<hidedmd>True</hidedmd>`n, %tempXMLStringOrig% Else FileAppend, `t`t<hidedmd>False</hidedmd>`n, %tempXMLStringOrig% GuiControlGet, XMLHideBG If (XMLHideBG=1) FileAppend, `t`t<hidebackglass>True</hidebackglass>`n, %tempXMLStringOrig% Else FileAppend, `t`t<hidebackglass>False</hidebackglass>`n, %tempXMLStringOrig% GuiControlGet, XMLEnabled If (XMLEnabled=1) FileAppend, `t`t<enabled>True</enabled>`n, %tempXMLStringOrig% Else FileAppend, `t`t<enabled>False</enabled>`n, %tempXMLStringOrig% GuiControlGet, XMLRating XMLRating := XMLRating-1 FileAppend, `t`t<rating>%XMLRating%</rating>`n, %tempXMLStringOrig% GuiControlGet, XMLAltExe GuiControlGet, XMLAltExeName If (XMLAltExe = 2) FileAppend, `t`t<alternateExe>%XMLAltExeName%</alternateExe>`n, %tempXMLStringOrig% Else If (XMLAltExe = 3) FileAppend, `t`t<Exe>%XMLAltExeName%</alternateExe>`n, %tempXMLStringOrig% FileAppend, `t</game>`n, %tempXMLStringOrig% FileAppend, </menu>`n, %tempXMLStringOrig% Gui, Destroy Return XMLDB2S: IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S Return Else IfExist, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.exe Return Else ;Let user select DirectB2S file to rename FileSelectFile, XMLFilePicked,,%DragAndDropFileDir%,,*.directb2s IfExist, %XMLFilePicked% { SetTimer, DB2SButtonNames, 50 Msgbox, 3, DirectB2S File Rename, Create a copy of the DirectB2S file and rename it? IfMsgBox, Yes ; Copy and rename the file { GuiControl ,, XDB2S, DB2S Found FileCopy, %XMLFilePicked%, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S, 1 } Else IfMsgBox, No ; Just rename the file { FileMove, %XMLFilePicked%, %DragAndDropFileDir%\%DragAndDropFileNameOnly%.directB2S, 1 GuiControl ,, XDB2S, DB2S Found } } Return DB2SButtonNames: IfWinNotExist, DirectB2S File Rename return ; Keep waiting. SetTimer, DB2SButtonNames, off WinActivate ControlSetText, Button1, &Copy&&Rename ControlSetText, Button2, &Just Rename return ; Release 1.0 Initial release Nov 11, 2015 ; Create playfield, backglass, dmd videos and/or images automatically based on PinballX setup ; Release 1.1 Fix bug if VisualPinball system is disabled (Dec 2015) ; Release 1.2 Skip table if table is disabled in Game Manager/XML (Jan 9, 2016) ; Add <AlternateExe> and <exe> xml tag support ; Add support for & and ® and ' in Table and Description names ; Check if vpt or vpx file exists, skip if not found ; Detects if Wheel Images or DirectB2S/B2S.exe are missing ; PinballX FTP users can enable automatic Wheel download support ; If PIN2DMD.exe found, it will reset PIN2DMD between tables ; 1.3 changes Feb 7, 2016 ; New recording mode added: "Record complete media set for new tables only" If any media is found, the table is skipped. Only tables with no media are recorded. This might eliminate the need for the drag and drop feature, since this leaves your existing Pinballx Media set unchanged, i.e if you do not have DMD images for some existing tables, PBX Recorder will not try to create them ; Drag and drop .vpt/.vpx file onto PBXrecorder to record only one table (Table must be exist in the PinballX xml files) ; New option to record video in .mp4 or existing .f4v. Now checks for existing .f4v or .mp4 or any file. ; New option to save Media filenames based on description name or table name ; Speed up the scanning of tables for people with larger libraries ; Improve DMD recording success by forcing dvd dimensions to an even pixel value ; Bug fix: Enable recordings for VP xml systems missing the enabled xml tag ; 1.4 changes Apr 7, 2016 ; New dialog to add table to Pinballx XML file ; PAUSE and RESUME support to allow table script changes before recording. Double tap PAUSE to record immediately ; 1.4FP May 2, 2016 ; Future Pinball support with playfield capture via OBS Studio ; Add support for ™ and recognition of * (i.e, *) in Table and Description names ; Some minor clean up for unused ErrorLevel parameters ; Add right click support (Play with VP, Record with PBXRecorder) ;todo: create reg entries ;todo: detect xml file to default to ;todo list duplicates xmls entries. ;todo support [xxx] for wheel download. ;todo list tables not in the xml file ;todo switch ini parsing to use split string function ; possible bug. recext not correct after modifying ini Changes from 1.4 ; 1.4FP Future Pinball support with playfield capture via OBS Studio ; Add support for ™ and recognition of * (i.e, *) in Table and Description names ; Some minor clean up for unused ErrorLevel parameters Again thanks to gtxjoe for allowing mods to his source code. The links to download the config file is broken, can someone repost. I would like to use pbx to record future pinball tables. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.