1
1
import asyncio
2
+ import threading
2
3
from datetime import datetime , timedelta
3
4
4
5
from ..messages .message_pusher import MessagePusher
10
11
from .stream_manager import LiveStreamRecorder
11
12
12
13
14
+ class GlobalRecordingState :
15
+ recordings = []
16
+ lock = threading .Lock ()
17
+
18
+
13
19
class RecordingManager :
14
20
def __init__ (self , app ):
15
21
self .app = app
16
22
self .settings = app .settings
17
- self .recordings = []
18
23
self .periodic_task_started = False
19
24
self .loop_time_seconds = None
20
25
self .app .language_manager .add_observer (self )
@@ -23,6 +28,14 @@ def __init__(self, app):
23
28
self .load ()
24
29
self .initialize_dynamic_state ()
25
30
31
+ @property
32
+ def recordings (self ):
33
+ return GlobalRecordingState .recordings
34
+
35
+ @recordings .setter
36
+ def recordings (self , value ):
37
+ raise AttributeError ("Please use add_recording/update_recording methods to modify data" )
38
+
26
39
def load (self ):
27
40
language = self .app .language_manager .language
28
41
for key in ("recording_manager" , "video_quality" ):
@@ -31,7 +44,8 @@ def load(self):
31
44
def load_recordings (self ):
32
45
"""Load recordings from a JSON file into objects."""
33
46
recordings_data = self .app .config_manager .load_recordings_config ()
34
- self .recordings = [Recording .from_dict (rec ) for rec in recordings_data ]
47
+ if not GlobalRecordingState .recordings :
48
+ GlobalRecordingState .recordings = [Recording .from_dict (rec ) for rec in recordings_data ]
35
49
logger .info (f"Live Recordings: Loaded { len (self .recordings )} items" )
36
50
37
51
def initialize_dynamic_state (self ):
@@ -42,11 +56,31 @@ def initialize_dynamic_state(self):
42
56
recording .loop_time_seconds = self .loop_time_seconds
43
57
recording .update_title (self ._ [recording .quality ])
44
58
45
- async def update_recording (self , recording : Recording , updated_info : dict ):
59
+ async def add_recording (self , recording ):
60
+ with GlobalRecordingState .lock :
61
+ GlobalRecordingState .recordings .append (recording )
62
+ await self .persist_recordings ()
63
+
64
+ async def remove_recording (self , recording : Recording ):
65
+ with GlobalRecordingState .lock :
66
+ GlobalRecordingState .recordings .remove (recording )
67
+ await self .persist_recordings ()
68
+
69
+ async def clear_all_recordings (self ):
70
+ with GlobalRecordingState .lock :
71
+ GlobalRecordingState .recordings .clear ()
72
+ await self .persist_recordings ()
73
+
74
+ async def persist_recordings (self ):
75
+ """Persist recordings to a JSON file."""
76
+ data_to_save = [rec .to_dict () for rec in self .recordings ]
77
+ await self .app .config_manager .save_recordings_config (data_to_save )
78
+
79
+ async def update_recording_card (self , recording : Recording , updated_info : dict ):
46
80
"""Update an existing recording object and persist changes to a JSON file."""
47
81
if recording :
48
82
recording .update (updated_info )
49
- self .app .page .run_task (self .save_to_json )
83
+ self .app .page .run_task (self .persist_recordings )
50
84
51
85
@staticmethod
52
86
async def _update_recording (
@@ -74,9 +108,10 @@ async def start_monitor_recording(self, recording: Recording, auto_save: bool =
74
108
selected = False ,
75
109
)
76
110
self .app .page .run_task (self .check_if_live , recording )
77
- self .app .page .run_task (self .app .record_card_manager .update_cards , recording )
111
+ self .app .page .run_task (self .app .record_card_manager .update_card , recording )
112
+ self .app .page .pubsub .send_others_on_topic ("update" , recording )
78
113
if auto_save :
79
- self .app .page .run_task (self .save_to_json )
114
+ self .app .page .run_task (self .persist_recordings )
80
115
81
116
async def stop_monitor_recording (self , recording : Recording , auto_save : bool = True ):
82
117
"""
@@ -91,9 +126,10 @@ async def stop_monitor_recording(self, recording: Recording, auto_save: bool = T
91
126
selected = False ,
92
127
)
93
128
self .stop_recording (recording )
94
- self .app .page .run_task (self .app .record_card_manager .update_cards , recording )
129
+ self .app .page .run_task (self .app .record_card_manager .update_card , recording )
130
+ self .app .page .pubsub .send_others_on_topic ("update" , recording )
95
131
if auto_save :
96
- self .app .page .run_task (self .save_to_json )
132
+ self .app .page .run_task (self .persist_recordings )
97
133
98
134
async def start_monitor_recordings (self ):
99
135
"""
@@ -105,7 +141,7 @@ async def start_monitor_recordings(self):
105
141
for recording in pre_start_monitor_recordings :
106
142
if cards_obj [recording .rec_id ]["card" ].visible :
107
143
self .app .page .run_task (self .start_monitor_recording , recording , auto_save = False )
108
- self .app .page .run_task (self .save_to_json )
144
+ self .app .page .run_task (self .persist_recordings )
109
145
logger .info (f"Batch Start Monitor Recordings: { [i .rec_id for i in pre_start_monitor_recordings ]} " )
110
146
111
147
async def stop_monitor_recordings (self , selected_recordings : list [Recording | None ] | None = None ):
@@ -119,19 +155,18 @@ async def stop_monitor_recordings(self, selected_recordings: list[Recording | No
119
155
for recording in pre_stop_monitor_recordings :
120
156
if cards_obj [recording .rec_id ]["card" ].visible :
121
157
self .app .page .run_task (self .stop_monitor_recording , recording , auto_save = False )
122
- self .app .page .run_task (self .save_to_json )
158
+ self .app .page .run_task (self .persist_recordings )
123
159
logger .info (f"Batch Stop Monitor Recordings: { [i .rec_id for i in pre_stop_monitor_recordings ]} " )
124
160
125
161
async def get_selected_recordings (self ):
126
162
return [recording for recording in self .recordings if recording .selected ]
127
163
128
- def remove_recordings (self , recordings : list [Recording ]):
164
+ async def remove_recordings (self , recordings : list [Recording ]):
129
165
"""Remove a recording from the list and update the JSON file."""
130
166
for recording in recordings :
131
167
if recording in self .recordings :
132
- self .recordings . remove (recording )
168
+ await self .remove_recording (recording )
133
169
logger .info (f"Delete Items: { recording .rec_id } -{ recording .streamer_name } " )
134
- self .app .page .run_task (self .save_to_json )
135
170
136
171
def find_recording_by_id (self , rec_id : str ):
137
172
"""Find a recording by its ID (hash of dict representation)."""
@@ -140,11 +175,6 @@ def find_recording_by_id(self, rec_id: str):
140
175
return rec
141
176
return None
142
177
143
- async def save_to_json (self ):
144
- """Persist recordings to a JSON file."""
145
- recordings_data = [rec .to_dict () for rec in self .recordings ]
146
- await self .app .config_manager .save_recordings_config (recordings_data )
147
-
148
178
async def check_all_live_status (self ):
149
179
"""Check the live status of all recordings and update their display titles."""
150
180
for recording in self .recordings :
@@ -264,7 +294,8 @@ async def check_if_live(self, recording: Recording):
264
294
self .start_update (recording )
265
295
self .app .page .run_task (recorder .start_recording , stream_info )
266
296
267
- self .app .page .run_task (self .app .record_card_manager .update_cards , recording )
297
+ self .app .page .run_task (self .app .record_card_manager .update_card , recording )
298
+ self .app .page .pubsub .send_others_on_topic ("update" , recording )
268
299
269
300
else :
270
301
recording .status_info = RecordingStatus .MONITORING
@@ -278,8 +309,9 @@ async def check_if_live(self, recording: Recording):
278
309
"display_title" : title ,
279
310
}
280
311
)
281
- self .app .page .run_task (self .app .record_card_manager .update_cards , recording )
282
- self .app .page .run_task (self .save_to_json )
312
+ self .app .page .run_task (self .app .record_card_manager .update_card , recording )
313
+ self .app .page .pubsub .send_others_on_topic ("update" , recording )
314
+ self .app .page .run_task (self .persist_recordings )
283
315
284
316
@staticmethod
285
317
def start_update (recording : Recording ):
@@ -323,8 +355,9 @@ def get_duration(self, recording: Recording):
323
355
return str (total_duration ).split ("." )[0 ]
324
356
325
357
async def delete_recording_cards (self , recordings : list [Recording ]):
326
- self .remove_recordings (recordings )
327
358
self .app .page .run_task (self .app .record_card_manager .remove_recording_card , recordings )
359
+ self .app .page .pubsub .send_others_on_topic ('delete' , recordings )
360
+ await self .remove_recordings (recordings )
328
361
329
362
async def check_free_space (self , output_dir : str | None = None ):
330
363
disk_space_limit = float (self .settings .user_config .get ("recording_space_threshold" ))
@@ -342,4 +375,4 @@ async def check_free_space(self, output_dir: str | None = None):
342
375
)
343
376
344
377
else :
345
- self .app .recording_enabled = True
378
+ self .app .recording_enabled = True
0 commit comments