@@ -9,8 +9,10 @@ const gdqGreen2 = [0, 255, 0];
99let screenshotBase64 = '' ;
1010let connectedToOBS = false ;
1111let obsConnectionError = '' ;
12- let cropItem : null | ( sceneItemRef & crop & { width : number ; height : number } ) =
13- null ;
12+ let obsUpdateTimeout : NodeJS . Timeout | null = null ;
13+ let cropItem :
14+ | null
15+ | ( sceneItemRef & crop & { width : number ; height : number } ) = null ;
1416let cropSide : 'left' | 'right' | 'top' | 'bottom' | null = null ;
1517let targetCrop : crop | null = null ;
1618let initialCrop : crop | null = null ;
@@ -398,7 +400,14 @@ const reInitEvents = [
398400function subscribeToChanges ( ) {
399401 if ( ! subscribed )
400402 for ( let i = 0 ; i < reInitEvents . length ; i ++ ) {
401- obs . on ( reInitEvents [ i ] , initOBS ) ;
403+ obs . on ( reInitEvents [ i ] , ( ) => {
404+ if ( obsUpdateTimeout ) {
405+ clearTimeout ( obsUpdateTimeout ) ;
406+ }
407+ obsUpdateTimeout = setTimeout ( ( ) => {
408+ initOBS ( ) ;
409+ } , 200 ) ;
410+ } ) ;
402411 }
403412 subscribed = true ;
404413}
@@ -543,14 +552,15 @@ function populateViewportsFromActiveFeed() {
543552 . send ( 'GetSceneItemList' , { sceneName : selectedFeedsScene } )
544553 . then ( async ( data ) => {
545554 sceneItemList = data . sceneItems ;
555+ const viewportFeeds : viewport [ 'assignedFeeds' ] = [ ] ;
546556 for ( let i = 0 ; i < data . sceneItems . length ; i ++ ) {
547557 await obs
548558 . send ( 'GetSceneItemProperties' , {
549559 'scene-name' : selectedFeedsScene ,
550560 item : { id : data . sceneItems [ i ] . itemId } ,
551561 } )
552562 . then ( ( data ) => {
553- const viewportFeed : viewport [ 'assignedFeeds' ] [ number ] = {
563+ viewportFeeds . push ( {
554564 'scene-name' : selectedFeedsScene ,
555565 item : { id : data . itemId , name : data . name } ,
556566 type : sceneItemList [ i ] . sourceKind ,
@@ -560,61 +570,97 @@ function populateViewportsFromActiveFeed() {
560570 bottom : data . crop . bottom ,
561571 width : data . sourceWidth ,
562572 height : data . sourceHeight ,
563- } ;
564- let assigned = false ;
565- for ( let i = 0 ; i < currentSceneViewports . length ; i ++ ) {
573+ x : data . position . x ,
574+ y : data . position . y ,
575+ boundsWidth : data . bounds . x ,
576+ boundsHeight : data . bounds . y ,
577+ } ) ;
578+ } )
579+ . catch ( obsError ) ;
580+ }
581+ let i = 0 ;
582+ let productiveLoop = false ;
583+ while ( i < viewportFeeds . length ) {
584+ let assigned = false ;
585+ for ( let j = 0 ; j < currentSceneViewports . length ; j ++ ) {
586+ if (
587+ viewportSearchBoxes [ j ] . x == viewportFeeds [ i ] . x &&
588+ viewportSearchBoxes [ j ] . y == viewportFeeds [ i ] . y
589+ ) {
590+ if (
591+ viewportSearchBoxes [ j ] . width == viewportFeeds [ i ] . boundsWidth &&
592+ viewportSearchBoxes [ j ] . height == viewportFeeds [ i ] . boundsHeight
593+ ) {
594+ currentSceneViewports [ j ] . assignedFeeds . push ( viewportFeeds [ i ] ) ;
566595 if (
567- viewportSearchBoxes [ i ] . x == data . position . x &&
568- viewportSearchBoxes [ i ] . y == data . position . y
569- ) {
570- if (
571- viewportSearchBoxes [ i ] . width == data . bounds . x &&
572- viewportSearchBoxes [ i ] . height == data . bounds . y
573- ) {
574- currentSceneViewports [ i ] . assignedFeeds . push ( viewportFeed ) ;
575- if (
576- currentSceneViewports [ i ] . rows > 1 ||
577- currentSceneViewports [ i ] . columns > 1
578- )
579- viewportSearchBoxes [ i ] = getViewPortBoundingBoxes (
580- currentSceneViewports [ i ]
581- ) [ currentSceneViewports [ i ] . assignedFeeds . length ] ;
596+ currentSceneViewports [ j ] . rows > 1 ||
597+ currentSceneViewports [ j ] . columns > 1
598+ )
599+ viewportSearchBoxes [ j ] = getViewPortBoundingBoxes (
600+ currentSceneViewports [ j ]
601+ ) [ currentSceneViewports [ j ] . assignedFeeds . length ] ;
602+ if ( ! viewportSearchBoxes [ j ] )
603+ viewportSearchBoxes [ j ] = {
604+ x : - 1 ,
605+ y : - 1 ,
606+ width : - 1 ,
607+ height : - 1 ,
608+ } ;
609+ productiveLoop = true ;
610+ assigned = true ;
611+ viewportFeeds . splice ( i , 1 ) ;
612+ break ;
613+ } else if ( currentSceneViewports [ j ] . assignedFeeds . length == 0 ) {
614+ const possibleWidth : number [ ] = [ NaN ] ; //array index corresponds to number of columns, which can't be zero
615+ for ( let k = 1 ; k <= 4 ; k ++ ) {
616+ possibleWidth . push (
617+ Math . round ( currentSceneViewports [ j ] . width / k )
618+ ) ;
619+ }
620+ const columns = possibleWidth . indexOf (
621+ viewportFeeds [ i ] . boundsWidth
622+ ) ;
623+ if ( columns > 0 ) {
624+ const possibleHeight : number [ ] = [ NaN ] ; //array index corresponds to number of rows, which can't be zero
625+ for ( let k = 1 ; k <= 4 ; k ++ ) {
626+ possibleHeight . push (
627+ Math . round ( currentSceneViewports [ j ] . height / k )
628+ ) ;
629+ }
630+ const rows = possibleHeight . indexOf (
631+ viewportFeeds [ i ] . boundsHeight
632+ ) ;
633+ if ( rows > 0 ) {
634+ currentSceneViewports [ j ] . rows = rows ;
635+ currentSceneViewports [ j ] . columns = columns ;
636+ currentSceneViewports [ j ] . assignedFeeds . push ( viewportFeeds [ i ] ) ;
637+ viewportSearchBoxes [ j ] = getViewPortBoundingBoxes (
638+ currentSceneViewports [ j ]
639+ ) [ currentSceneViewports [ j ] . assignedFeeds . length ] ;
640+ if ( ! viewportSearchBoxes [ j ] )
641+ viewportSearchBoxes [ j ] = {
642+ x : - 1 ,
643+ y : - 1 ,
644+ width : - 1 ,
645+ height : - 1 ,
646+ } ;
647+ productiveLoop = true ;
582648 assigned = true ;
649+ viewportFeeds . splice ( i , 1 ) ;
583650 break ;
584- } else if ( currentSceneViewports [ i ] . assignedFeeds . length == 0 ) {
585- const possibleWidth : number [ ] = [ NaN ] ;
586- for ( let j = 1 ; j <= 4 ; j ++ ) {
587- possibleWidth . push (
588- Math . round ( currentSceneViewports [ i ] . width / j )
589- ) ;
590- }
591- const columns = possibleWidth . indexOf ( data . bounds . x ) ;
592- if ( columns > 0 ) {
593- const possibleHeight : number [ ] = [ NaN ] ;
594- for ( let j = 1 ; j <= 4 ; j ++ ) {
595- possibleHeight . push (
596- Math . round ( currentSceneViewports [ i ] . height / j )
597- ) ;
598- }
599- const rows = possibleHeight . indexOf ( data . bounds . y ) ;
600- if ( rows > 0 ) {
601- currentSceneViewports [ i ] . rows = rows ;
602- currentSceneViewports [ i ] . columns = columns ;
603- currentSceneViewports [ i ] . assignedFeeds . push ( viewportFeed ) ;
604- viewportSearchBoxes [ i ] = getViewPortBoundingBoxes (
605- currentSceneViewports [ i ]
606- ) [ currentSceneViewports [ i ] . assignedFeeds . length ] ;
607- assigned = true ;
608- break ;
609- }
610- }
611651 }
612652 }
613653 }
614- if ( ! assigned ) unassignedFeeds . push ( viewportFeed ) ;
615- } )
616- . catch ( obsError ) ;
654+ }
655+ }
656+ //if (!assigned) unassignedFeeds.push(viewportFeeds[i]);
657+ if ( ! assigned ) i ++ ;
658+ if ( i == viewportFeeds . length && productiveLoop == true ) {
659+ i = 0 ;
660+ productiveLoop = false ;
661+ }
617662 }
663+ unassignedFeeds = viewportFeeds ;
618664 } )
619665 . catch ( obsError ) ;
620666}
@@ -759,7 +805,8 @@ async function refreshViewportsDiv() {
759805 if (
760806 currentSceneViewports [ i ] &&
761807 currentSceneViewports [ i ] . rows >
762- currentSceneViewports [ i ] . assignedFeeds . length
808+ currentSceneViewports [ i ] . assignedFeeds . length &&
809+ currentSceneViewports [ i ] . assignedFeeds . length > 0
763810 )
764811 currentSceneViewports [ i ] . rows =
765812 currentSceneViewports [ i ] . assignedFeeds . length ;
@@ -781,13 +828,88 @@ async function refreshViewportsDiv() {
781828 refreshCropDiv ( ) ;
782829 } ;
783830 sourceDiv . appendChild ( cropIcon ) ;
831+ const upIcon = document . createElement ( 'img' ) ;
832+ upIcon . classList . add ( 'icon' ) ;
833+ upIcon . style . float = 'right' ;
834+ if ( j > 0 ) {
835+ upIcon . src = icons . up ;
836+ upIcon . onclick = ( ) => {
837+ swapFeeds ( viewportFeeds , j , j - 1 ) ;
838+ } ;
839+ } else upIcon . src = icons . blank ;
840+ sourceDiv . appendChild ( upIcon ) ;
841+ if ( j < viewportFeeds . length - 1 ) {
842+ const downIcon = document . createElement ( 'img' ) ;
843+ downIcon . classList . add ( 'icon' ) ;
844+ downIcon . style . float = 'right' ;
845+ downIcon . src = icons . down ;
846+ downIcon . onclick = ( ) => {
847+ swapFeeds ( viewportFeeds , j , j + 1 ) ;
848+ } ;
849+ sourceDiv . appendChild ( downIcon ) ;
850+ }
784851 viewportSourcesDiv . appendChild ( sourceDiv ) ;
785852 }
786853 listDiv . appendChild ( viewportSourcesDiv ) ;
787854 }
788855 refreshFooter ( ) ;
789856}
790857
858+ function swapFeeds (
859+ viewportFeeds : typeof unassignedFeeds ,
860+ index1 : number ,
861+ index2 : number
862+ ) {
863+ const feed1 = viewportFeeds [ index1 ] ;
864+ const feed2 = viewportFeeds [ index2 ] ;
865+ const swapX = feed2 . x ;
866+ const swapY = feed2 . y ;
867+ const swapWidth = feed2 . boundsWidth ;
868+ const swapHeight = feed2 . boundsHeight ;
869+ feed2 . x = feed1 . x ;
870+ feed2 . y = feed1 . y ;
871+ feed2 . boundsWidth = feed1 . boundsWidth ;
872+ feed2 . boundsHeight = feed1 . boundsHeight ;
873+ feed1 . x = swapX ;
874+ feed1 . y = swapY ;
875+ feed1 . boundsWidth = swapWidth ;
876+ feed1 . boundsHeight = swapHeight ;
877+ unsubscribeToChanges ( ) ;
878+ obs
879+ . send ( 'SetSceneItemProperties' , {
880+ 'scene-name' : selectedFeedsScene ,
881+ item : feed1 . item ,
882+ position : { x : feed1 . x , y : feed1 . y } ,
883+ scale : { } ,
884+ crop : { } ,
885+ bounds : {
886+ x : feed1 . boundsWidth ,
887+ y : feed1 . boundsHeight ,
888+ } ,
889+ } )
890+ . then ( ( ) => {
891+ return obs . send ( 'SetSceneItemProperties' , {
892+ 'scene-name' : selectedFeedsScene ,
893+ item : feed2 . item ,
894+ position : { x : feed2 . x , y : feed2 . y } ,
895+ scale : { } ,
896+ crop : { } ,
897+ bounds : {
898+ x : feed2 . boundsWidth ,
899+ y : feed2 . boundsHeight ,
900+ } ,
901+ } ) ;
902+ } )
903+ . then ( ( ) => {
904+ const swap = viewportFeeds [ index2 ] ;
905+ viewportFeeds [ index2 ] = viewportFeeds [ index1 ] ;
906+ viewportFeeds [ index1 ] = swap ;
907+ refreshViewportsDiv ( ) ;
908+ subscribeToChanges ( ) ;
909+ } )
910+ . catch ( console . error ) ;
911+ }
912+
791913async function removeUnassignedSources ( ) {
792914 unsubscribeToChanges ( ) ;
793915 for ( let i = 0 ; i < unassignedFeeds . length ; i ++ ) {
@@ -840,6 +962,12 @@ async function arrangeViewportFeeds(viewport: viewport) {
840962 y : boxes [ i ] . height ,
841963 } ,
842964 } )
965+ . then ( ( ) => {
966+ feed . x = boxes [ i ] . x ;
967+ feed . y = boxes [ i ] . y ;
968+ feed . boundsWidth = boxes [ i ] . width ;
969+ feed . boundsHeight = boxes [ i ] . height ;
970+ } )
843971 . catch ( console . error ) ;
844972 }
845973 subscribeToChanges ( ) ;
@@ -1167,6 +1295,10 @@ async function addSourceToViewport(
11671295 bottom : 0 ,
11681296 width : source . source_cx ,
11691297 height : source . source_cy ,
1298+ x : viewport . x ,
1299+ y : viewport . y ,
1300+ boundsWidth : viewport . width ,
1301+ boundsHeight : viewport . height ,
11701302 } ;
11711303 return obs . send ( 'SetSceneItemProperties' , {
11721304 'scene-name' : scene ,
0 commit comments