Spaces:
Running
Running
v2.37-fill-span: bound watchdog fill exemption + pump renewal by whole fill episode (fill_until)
Browse files
ingest.py
CHANGED
|
@@ -6,7 +6,7 @@ import os, threading, time
|
|
| 6 |
from datetime import datetime
|
| 7 |
from zoneinfo import ZoneInfo
|
| 8 |
|
| 9 |
-
APP_VERSION = 'relay-v2.
|
| 10 |
|
| 11 |
|
| 12 |
def env_rtmp_destination():
|
|
|
|
| 6 |
from datetime import datetime
|
| 7 |
from zoneinfo import ZoneInfo
|
| 8 |
|
| 9 |
+
APP_VERSION = 'relay-v2.37-fill-span'
|
| 10 |
|
| 11 |
|
| 12 |
def env_rtmp_destination():
|
relay.py
CHANGED
|
@@ -763,7 +763,8 @@ class Sender:
|
|
| 763 |
# خياطة ليس دليل موت خرج (مقيس: 13:06:13 و13:21:46 و10:24:57).
|
| 764 |
# نجدّد بمهل قصيرة ما دام الحشو قائمًا، وسقف الحشو (90 ث) نفسه
|
| 765 |
# يحدّ الصبر الكلي، فلا تعليق أبديًا ولا قتل لجلسة تُنقَذ.
|
| 766 |
-
if sess is not None and sess.get('filling') and not sess.get('force_stop')
|
|
|
|
| 767 |
deadline = time.monotonic() + 2.0
|
| 768 |
continue
|
| 769 |
raise SourceStalled('أنبوب FFmpeg ممتلئ ولا يقرأ منذ %.0f ث' % max(0.0, -left))
|
|
@@ -799,7 +800,7 @@ class Sender:
|
|
| 799 |
stdin، ويوتيوب يبقى مستقبِلًا على آخر ما وصل — لذا يُقاس تدفق البيانات لا حالة العملية.
|
| 800 |
"""
|
| 801 |
sess.setdefault('stdin_lock', threading.Lock())
|
| 802 |
-
sess.setdefault('filling', False); sess.setdefault('filling_at', 0.0); sess.setdefault('fill_emit_at', 0.0); sess.setdefault('reattach_at', 0.0)
|
| 803 |
it = response.iter_content(None).__iter__()
|
| 804 |
deadline = time.monotonic() + sess['max_seconds']
|
| 805 |
chunk_wait = min(read_timeout, max(1.0, self._stall_seconds() / 3.0)) if self._stall_seconds() else read_timeout
|
|
@@ -1089,7 +1090,7 @@ class Sender:
|
|
| 1089 |
'stall_reason': '', 'spawned': False, 'spawn_error': '',
|
| 1090 |
'writing': False, 'output_failure': False, 'connection_event': False,
|
| 1091 |
'ff_last': time.monotonic(),
|
| 1092 |
-
'stdin_lock': threading.Lock(), 'filling': False, 'filling_at': 0.0, 'fill_emit_at': 0.0, 'reattach_at': 0.0}
|
| 1093 |
self.set(status='الاتصال بيوتيوب', source=candidate['label'], output_seconds=0,
|
| 1094 |
last_output_at=None, stalled=False, last_source_at=sess['last'], source_bytes=0,
|
| 1095 |
rtmp_phase='')
|
|
@@ -1285,6 +1286,7 @@ class Sender:
|
|
| 1285 |
sess['filling']=False;continue
|
| 1286 |
if fill_state['started'] is None:
|
| 1287 |
fill_state['started']=now_f;fill_state['last_emit']=0.0
|
|
|
|
| 1288 |
self.log(user,'[FILL] صمت المصدر %.0f ث؛ حشو بإطار مجمّد حتى لا يرى يوتيوب فجوة (سقف %.0f ث)'%(silent_for,fill_max))
|
| 1289 |
log_event(user,'GAP_FILL_START',{'silent_seconds':round(silent_for,1),'cap_seconds':fill_max})
|
| 1290 |
telemetry_event(tele_key,user,'GAP_FILL_START',{'silent_seconds':round(silent_for,1),'cap_seconds':fill_max})
|
|
@@ -1406,7 +1408,7 @@ class Sender:
|
|
| 1406 |
continue
|
| 1407 |
if (stall_limit and now - _fresh > stall_limit and
|
| 1408 |
(not recent_attach or sess.get('output_failure') or sess.get('writing')) and
|
| 1409 |
-
not (sess.get('filling') and now
|
| 1410 |
(not sess.get('swapping') or swap_for > stall_limit)):
|
| 1411 |
# A full stdin pipe proves the source delivered a chunk but FFmpeg stopped
|
| 1412 |
# consuming it. Reopening TikTok cannot repair a blocked RTMPS output.
|
|
|
|
| 763 |
# خياطة ليس دليل موت خرج (مقيس: 13:06:13 و13:21:46 و10:24:57).
|
| 764 |
# نجدّد بمهل قصيرة ما دام الحشو قائمًا، وسقف الحشو (90 ث) نفسه
|
| 765 |
# يحدّ الصبر الكلي، فلا تعليق أبديًا ولا قتل لجلسة تُنقَذ.
|
| 766 |
+
if (sess is not None and sess.get('filling') and not sess.get('force_stop')
|
| 767 |
+
and time.monotonic() < float(sess.get('fill_until') or 0)):
|
| 768 |
deadline = time.monotonic() + 2.0
|
| 769 |
continue
|
| 770 |
raise SourceStalled('أنبوب FFmpeg ممتلئ ولا يقرأ منذ %.0f ث' % max(0.0, -left))
|
|
|
|
| 800 |
stdin، ويوتيوب يبقى مستقبِلًا على آخر ما وصل — لذا يُقاس تدفق البيانات لا حالة العملية.
|
| 801 |
"""
|
| 802 |
sess.setdefault('stdin_lock', threading.Lock())
|
| 803 |
+
sess.setdefault('filling', False); sess.setdefault('filling_at', 0.0); sess.setdefault('fill_emit_at', 0.0); sess.setdefault('reattach_at', 0.0); sess.setdefault('fill_since', 0.0); sess.setdefault('fill_until', 0.0)
|
| 804 |
it = response.iter_content(None).__iter__()
|
| 805 |
deadline = time.monotonic() + sess['max_seconds']
|
| 806 |
chunk_wait = min(read_timeout, max(1.0, self._stall_seconds() / 3.0)) if self._stall_seconds() else read_timeout
|
|
|
|
| 1090 |
'stall_reason': '', 'spawned': False, 'spawn_error': '',
|
| 1091 |
'writing': False, 'output_failure': False, 'connection_event': False,
|
| 1092 |
'ff_last': time.monotonic(),
|
| 1093 |
+
'stdin_lock': threading.Lock(), 'filling': False, 'filling_at': 0.0, 'fill_emit_at': 0.0, 'fill_since': 0.0, 'fill_until': 0.0, 'reattach_at': 0.0}
|
| 1094 |
self.set(status='الاتصال بيوتيوب', source=candidate['label'], output_seconds=0,
|
| 1095 |
last_output_at=None, stalled=False, last_source_at=sess['last'], source_bytes=0,
|
| 1096 |
rtmp_phase='')
|
|
|
|
| 1286 |
sess['filling']=False;continue
|
| 1287 |
if fill_state['started'] is None:
|
| 1288 |
fill_state['started']=now_f;fill_state['last_emit']=0.0
|
| 1289 |
+
sess['fill_since']=now_f;sess['fill_until']=now_f+fill_max+25.0
|
| 1290 |
self.log(user,'[FILL] صمت المصدر %.0f ث؛ حشو بإطار مجمّد حتى لا يرى يوتيوب فجوة (سقف %.0f ث)'%(silent_for,fill_max))
|
| 1291 |
log_event(user,'GAP_FILL_START',{'silent_seconds':round(silent_for,1),'cap_seconds':fill_max})
|
| 1292 |
telemetry_event(tele_key,user,'GAP_FILL_START',{'silent_seconds':round(silent_for,1),'cap_seconds':fill_max})
|
|
|
|
| 1408 |
continue
|
| 1409 |
if (stall_limit and now - _fresh > stall_limit and
|
| 1410 |
(not recent_attach or sess.get('output_failure') or sess.get('writing')) and
|
| 1411 |
+
not (sess.get('filling') and now<float(sess.get('fill_until') or 0)) and
|
| 1412 |
(not sess.get('swapping') or swap_for > stall_limit)):
|
| 1413 |
# A full stdin pipe proves the source delivered a chunk but FFmpeg stopped
|
| 1414 |
# consuming it. Reopening TikTok cannot repair a blocked RTMPS output.
|