mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-10-17 13:22:29 +02:00
magenta2 catchup adjuster
This commit is contained in:
Generated
+1
@@ -4,6 +4,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib/streaming_providers/base" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib/streaming_providers" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.12 (.venv)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
# streaming_providers/magenta2/catchup_adjuster.py
|
||||
"""
|
||||
Magenta2 catchup manifest adjuster.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from ...base.utils.logger import logger
|
||||
from ...base.utils.mpd_event_rewriter import get_mpd_event_rewriter
|
||||
|
||||
_MAGENTA2_EPG_SCHEME = "urn:de:dtag:eit:2017"
|
||||
_EVENT_MATCH_THRESHOLD_S = 300
|
||||
_EVENT_MATCH_THRESHOLD_S = 300 # 5 minutes - still used as fallback
|
||||
_SKIP_NEAR_END_THRESHOLD_S = 300 # Skip event if less than 5 minutes remaining
|
||||
|
||||
|
||||
class Magenta2CatchupAdjuster:
|
||||
@@ -16,16 +20,23 @@ class Magenta2CatchupAdjuster:
|
||||
"""
|
||||
Adjust Magenta2 catchup MPD to start at requested time.
|
||||
|
||||
Returns adjusted MPD content, or original if adjustment fails.
|
||||
Strategy for catchup seeking:
|
||||
1. Find the first event that starts AT OR AFTER the requested time
|
||||
(upcoming show) - this is what users typically want when seeking
|
||||
2. If no upcoming event exists, use the last event (requested time
|
||||
is after all events)
|
||||
3. Special case: If requested time is within an event AND that event
|
||||
has more than SKIP_NEAR_END_THRESHOLD_S remaining, join it in progress
|
||||
4. Otherwise, fall back to buffer offset calculation
|
||||
|
||||
This ensures seeking to "Meister des Alltags" at 08:40 correctly jumps
|
||||
to Meister's start at 08:42:44, not to the nearly-finished Tagesschau.
|
||||
"""
|
||||
rewriter = get_mpd_event_rewriter()
|
||||
requested_dt = datetime.fromtimestamp(requested_start_time, tz=timezone.utc)
|
||||
|
||||
try:
|
||||
# FIX: extract_events returns ExtractedEvents object, not tuple
|
||||
extracted = rewriter.extract_events(mpd_content, _MAGENTA2_EPG_SCHEME)
|
||||
|
||||
# Access events and availability_start from the object
|
||||
events = extracted.events
|
||||
ast = extracted.availability_start
|
||||
|
||||
@@ -33,27 +44,103 @@ class Magenta2CatchupAdjuster:
|
||||
logger.warning("Magenta2: no events found, using buffer offset")
|
||||
return rewriter.rewrite_by_buffer_offset(mpd_content, extracted, requested_dt)
|
||||
|
||||
# FIX: find_closest_event now takes ExtractedEvents as first argument
|
||||
best_event, diff = rewriter.find_closest_event(extracted, requested_dt)
|
||||
# Sort events by start time
|
||||
sorted_events = sorted(events, key=lambda ev: ev.wall_clock_start(ast))
|
||||
|
||||
if best_event and diff <= _EVENT_MATCH_THRESHOLD_S:
|
||||
# First, check if requested time falls within a long-running event
|
||||
current_event = None
|
||||
for ev in sorted_events:
|
||||
ev_start = ev.wall_clock_start(ast)
|
||||
ev_end = ev.wall_clock_end(ast)
|
||||
if ev_start <= requested_dt <= ev_end:
|
||||
current_event = ev
|
||||
break
|
||||
|
||||
if current_event:
|
||||
time_into_event = (requested_dt - current_event.wall_clock_start(ast)).total_seconds()
|
||||
time_remaining = current_event.duration_seconds() - time_into_event
|
||||
|
||||
# If we're near the end of the current event, skip to next event
|
||||
if time_remaining <= _SKIP_NEAR_END_THRESHOLD_S:
|
||||
logger.info(
|
||||
f"Magenta2: requested time near end of '{current_event.title}' "
|
||||
f"({time_remaining:.0f}s remaining), skipping to next event"
|
||||
)
|
||||
# Find next event after current_event
|
||||
current_index = sorted_events.index(current_event)
|
||||
if current_index + 1 < len(sorted_events):
|
||||
best_event = sorted_events[current_index + 1]
|
||||
ev_start = best_event.wall_clock_start(ast)
|
||||
logger.info(
|
||||
f"Magenta2: adjusting to next event '{best_event.title}' "
|
||||
f"(start={ev_start.isoformat()})"
|
||||
)
|
||||
return rewriter.rewrite_for_event(
|
||||
mpd_content, extracted, best_event,
|
||||
keep_other_events=False,
|
||||
force_static_if_ended=False,
|
||||
)
|
||||
else:
|
||||
# No next event, use buffer offset
|
||||
logger.info("Magenta2: no next event available, using buffer offset")
|
||||
return rewriter.rewrite_by_buffer_offset(mpd_content, extracted, requested_dt)
|
||||
else:
|
||||
# Join current event in progress (has substantial time remaining)
|
||||
logger.info(
|
||||
f"Magenta2: joining in-progress event '{current_event.title}' "
|
||||
f"({time_remaining:.0f}s remaining)"
|
||||
)
|
||||
return rewriter.rewrite_for_event(
|
||||
mpd_content, extracted, current_event,
|
||||
keep_other_events=False,
|
||||
force_static_if_ended=False,
|
||||
)
|
||||
|
||||
# Find the first event that starts AT OR AFTER requested time (upcoming show)
|
||||
best_event = None
|
||||
for ev in sorted_events:
|
||||
ev_start = ev.wall_clock_start(ast)
|
||||
if ev_start >= requested_dt:
|
||||
best_event = ev
|
||||
break
|
||||
|
||||
# If no upcoming event (requested time is after all events), take the last event
|
||||
if best_event is None and sorted_events:
|
||||
best_event = sorted_events[-1]
|
||||
logger.info(
|
||||
f"Magenta2: adjusting to event '{best_event.title}' "
|
||||
f"(start={best_event.wall_clock_start(ast).isoformat()}, diff={diff:.0f}s)"
|
||||
)
|
||||
return rewriter.rewrite_for_event(
|
||||
mpd_content, extracted, best_event,
|
||||
keep_other_events=False,
|
||||
force_static_if_ended=False,
|
||||
f"Magenta2: requested time after all events, using last event "
|
||||
f"'{best_event.title}'"
|
||||
)
|
||||
|
||||
logger.info(f"Magenta2: no close event match (diff={diff:.0f}s), using buffer offset")
|
||||
if best_event:
|
||||
ev_start = best_event.wall_clock_start(ast)
|
||||
diff = (ev_start - requested_dt).total_seconds()
|
||||
|
||||
# If the gap is very large (> threshold), consider buffer offset instead
|
||||
if abs(diff) <= _EVENT_MATCH_THRESHOLD_S:
|
||||
logger.info(
|
||||
f"Magenta2: adjusting to event '{best_event.title}' "
|
||||
f"(start={ev_start.isoformat()}, diff={diff:.0f}s from requested)"
|
||||
)
|
||||
return rewriter.rewrite_for_event(
|
||||
mpd_content, extracted, best_event,
|
||||
keep_other_events=False,
|
||||
force_static_if_ended=False,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"Magenta2: event match diff ({diff:.0f}s) exceeds threshold "
|
||||
f"({_EVENT_MATCH_THRESHOLD_S}s), using buffer offset"
|
||||
)
|
||||
return rewriter.rewrite_by_buffer_offset(mpd_content, extracted, requested_dt)
|
||||
|
||||
# No suitable event found - use buffer offset
|
||||
logger.info(f"Magenta2: no suitable event found for {requested_dt.isoformat()}, using buffer offset")
|
||||
return rewriter.rewrite_by_buffer_offset(mpd_content, extracted, requested_dt)
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Magenta2: cannot parse events ({e}), using buffer offset")
|
||||
try:
|
||||
# Fallback: try without scheme filter
|
||||
extracted = rewriter.extract_events(mpd_content)
|
||||
return rewriter.rewrite_by_buffer_offset(mpd_content, extracted, requested_dt)
|
||||
except ValueError:
|
||||
|
||||
Reference in New Issue
Block a user