vm_streamlabs_sync.py
· 4.5 KiB · Python
Eredeti
import asyncio
import logging
from collections import namedtuple
import voicemeeterlib
from pyslobs import ScenesService, config_from_ini_else_stdin, connection
class Observer:
"""
Observer class to handle scene switch events and perform corresponding actions.
Attributes:
_vm: An instance of the virtual mixer.
conn: Connection object to communicate with the Streamlabs ScenesService.
Methods:
__init__(vm, conn):
Initializes the Observer with a virtual mixer and streamlabs connection.
subscribe():
Subscribes to the scene switch event from the ScenesService.
on_switch_scene(_, message):
Handles the scene switch event and calls the appropriate method based on the scene name.
on_start():
Handles actions to be performed when the scene switches to 'START_TEST'.
on_brb():
Handles actions to be performed when the scene switches to 'BRB_TEST'.
on_end():
Handles actions to be performed when the scene switches to 'END_TEST'.
on_live():
Handles actions to be performed when the scene switches to 'LIVE_TEST'.
"""
def __init__(self, vm, conn):
self._vm = vm
self.conn = conn
async def subscribe(self):
await ScenesService(self.conn).scene_switched.subscribe(self.on_switch_scene)
async def on_switch_scene(self, _, message):
scene = message.get('name')
print(f'Switching to {scene}')
match scene:
case 'START_TEST':
await self.on_start()
case 'BRB_TEST':
await self.on_brb()
case 'END_TEST':
await self.on_end()
case 'LIVE_TEST':
await self.on_live()
case _:
pass
async def on_start(self):
self._vm.strip[0].mute = True
self._vm.strip[1].B1 = True
self._vm.strip[2].B2 = True
async def on_brb(self):
self._vm.strip[7].fadeto(0, 500)
self._vm.bus[0].mute = True
async def on_end(self):
self._vm.apply(
{
'strip-0': {'mute': True},
'strip-1': {'mute': True, 'B1': False},
'strip-2': {'mute': True, 'B1': False},
'vban-in-0': {'on': False},
}
)
async def on_live(self):
self._vm.strip[0].mute = False
self._vm.strip[7].fadeto(-6, 500)
self._vm.strip[7].A3 = True
self._vm.vban.instream[0].on = True
async def rotate_scenes(conn):
"""
Rotates through specific scenes and makes each one active for a short duration.
Args:
conn: The connection object to the ScenesService.
This function retrieves all scenes using the ScenesService, then iterates through
a predefined list of scene names ('START_TEST', 'BRB_TEST', 'END_TEST', 'LIVE_TEST').
For each matching scene, it makes the scene active and waits for 1 second before
moving to the next scene. Finally, it closes the connection.
"""
Scene = namedtuple('Scene', 'name id')
ss = ScenesService(conn)
scenes = await ss.get_scenes()
for scene in (Scene(s.name, s.id) for s in scenes):
if scene.name in ('START_TEST', 'BRB_TEST', 'END_TEST', 'LIVE_TEST'):
await ss.make_scene_active(scene.id)
await asyncio.sleep(1)
conn.close()
async def main():
"""
Main asynchronous function to initialize and run the application.
This function performs the following tasks:
1. Establishes a connection to the Voicemeeter API using the 'potato' version.
2. Creates a connection to Streamlabs using configuration from an INI file or standard input.
3. Initializes an observer to monitor and react to events from Voicemeeter and Streamlabs.
4. Runs background processing tasks concurrently, including:
- Streamlabs connection background processing
- Observer subscription to events
- Streamlabs scene rotation
The function uses asyncio.gather to run these tasks concurrently.
Note:
This function should be run within an asyncio event loop.
"""
with voicemeeterlib.api('potato') as vm:
conn = connection.SlobsConnection(config_from_ini_else_stdin())
await asyncio.gather(
conn.background_processing(),
Observer(vm, conn).subscribe(),
rotate_scenes(conn),
)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
1 | import asyncio |
2 | import logging |
3 | from collections import namedtuple |
4 | |
5 | import voicemeeterlib |
6 | from pyslobs import ScenesService, config_from_ini_else_stdin, connection |
7 | |
8 | |
9 | class Observer: |
10 | """ |
11 | Observer class to handle scene switch events and perform corresponding actions. |
12 | Attributes: |
13 | _vm: An instance of the virtual mixer. |
14 | conn: Connection object to communicate with the Streamlabs ScenesService. |
15 | Methods: |
16 | __init__(vm, conn): |
17 | Initializes the Observer with a virtual mixer and streamlabs connection. |
18 | subscribe(): |
19 | Subscribes to the scene switch event from the ScenesService. |
20 | on_switch_scene(_, message): |
21 | Handles the scene switch event and calls the appropriate method based on the scene name. |
22 | on_start(): |
23 | Handles actions to be performed when the scene switches to 'START_TEST'. |
24 | on_brb(): |
25 | Handles actions to be performed when the scene switches to 'BRB_TEST'. |
26 | on_end(): |
27 | Handles actions to be performed when the scene switches to 'END_TEST'. |
28 | on_live(): |
29 | Handles actions to be performed when the scene switches to 'LIVE_TEST'. |
30 | """ |
31 | |
32 | def __init__(self, vm, conn): |
33 | self._vm = vm |
34 | self.conn = conn |
35 | |
36 | async def subscribe(self): |
37 | await ScenesService(self.conn).scene_switched.subscribe(self.on_switch_scene) |
38 | |
39 | async def on_switch_scene(self, _, message): |
40 | scene = message.get('name') |
41 | print(f'Switching to {scene}') |
42 | match scene: |
43 | case 'START_TEST': |
44 | await self.on_start() |
45 | case 'BRB_TEST': |
46 | await self.on_brb() |
47 | case 'END_TEST': |
48 | await self.on_end() |
49 | case 'LIVE_TEST': |
50 | await self.on_live() |
51 | case _: |
52 | pass |
53 | |
54 | async def on_start(self): |
55 | self._vm.strip[0].mute = True |
56 | self._vm.strip[1].B1 = True |
57 | self._vm.strip[2].B2 = True |
58 | |
59 | async def on_brb(self): |
60 | self._vm.strip[7].fadeto(0, 500) |
61 | self._vm.bus[0].mute = True |
62 | |
63 | async def on_end(self): |
64 | self._vm.apply( |
65 | { |
66 | 'strip-0': {'mute': True}, |
67 | 'strip-1': {'mute': True, 'B1': False}, |
68 | 'strip-2': {'mute': True, 'B1': False}, |
69 | 'vban-in-0': {'on': False}, |
70 | } |
71 | ) |
72 | |
73 | async def on_live(self): |
74 | self._vm.strip[0].mute = False |
75 | self._vm.strip[7].fadeto(-6, 500) |
76 | self._vm.strip[7].A3 = True |
77 | self._vm.vban.instream[0].on = True |
78 | |
79 | |
80 | async def rotate_scenes(conn): |
81 | """ |
82 | Rotates through specific scenes and makes each one active for a short duration. |
83 | Args: |
84 | conn: The connection object to the ScenesService. |
85 | This function retrieves all scenes using the ScenesService, then iterates through |
86 | a predefined list of scene names ('START_TEST', 'BRB_TEST', 'END_TEST', 'LIVE_TEST'). |
87 | For each matching scene, it makes the scene active and waits for 1 second before |
88 | moving to the next scene. Finally, it closes the connection. |
89 | """ |
90 | |
91 | Scene = namedtuple('Scene', 'name id') |
92 | |
93 | ss = ScenesService(conn) |
94 | scenes = await ss.get_scenes() |
95 | for scene in (Scene(s.name, s.id) for s in scenes): |
96 | if scene.name in ('START_TEST', 'BRB_TEST', 'END_TEST', 'LIVE_TEST'): |
97 | await ss.make_scene_active(scene.id) |
98 | await asyncio.sleep(1) |
99 | conn.close() |
100 | |
101 | |
102 | async def main(): |
103 | """ |
104 | Main asynchronous function to initialize and run the application. |
105 | This function performs the following tasks: |
106 | 1. Establishes a connection to the Voicemeeter API using the 'potato' version. |
107 | 2. Creates a connection to Streamlabs using configuration from an INI file or standard input. |
108 | 3. Initializes an observer to monitor and react to events from Voicemeeter and Streamlabs. |
109 | 4. Runs background processing tasks concurrently, including: |
110 | - Streamlabs connection background processing |
111 | - Observer subscription to events |
112 | - Streamlabs scene rotation |
113 | The function uses asyncio.gather to run these tasks concurrently. |
114 | Note: |
115 | This function should be run within an asyncio event loop. |
116 | """ |
117 | |
118 | with voicemeeterlib.api('potato') as vm: |
119 | conn = connection.SlobsConnection(config_from_ini_else_stdin()) |
120 | await asyncio.gather( |
121 | conn.background_processing(), |
122 | Observer(vm, conn).subscribe(), |
123 | rotate_scenes(conn), |
124 | ) |
125 | |
126 | |
127 | if __name__ == '__main__': |
128 | logging.basicConfig(level=logging.INFO) |
129 | |
130 | asyncio.run(main()) |
131 |