MCPcopy Create free account
hub / github.com/Dispatcharr/Dispatcharr / stop

Method stop

apps/channels/api_views.py:3510–3578  ·  view source on GitHub ↗

Stop a recording early while retaining the partial content for playback.

(self, request, pk=None)

Source from the content-addressed store, hash-verified

3508
3509 @action(detail=True, methods=["post"], url_path="stop")
3510 def stop(self, request, pk=None):
3511 """Stop a recording early while retaining the partial content for playback."""
3512 instance = self.get_object()
3513
3514 cp = instance.custom_properties or {}
3515 current_status = cp.get("status", "")
3516
3517 # Reject stop on recordings that are already in a terminal state.
3518 # Without this guard, stop() would overwrite "completed" or
3519 # "interrupted" with "stopped", losing the original outcome.
3520 terminal = {"completed", "interrupted", "failed"}
3521 if current_status in terminal:
3522 return Response(
3523 {"success": False, "error": f"Recording is already {current_status}"},
3524 status=status.HTTP_409_CONFLICT,
3525 )
3526
3527 # Mark as stopped in the DB first so run_recording detects it.
3528 # This is the only operation that MUST be synchronous — run_recording reads
3529 # the status field to decide whether the stream disconnection was deliberate.
3530 cp["status"] = "stopped"
3531 cp["stopped_at"] = str(timezone.now())
3532 instance.custom_properties = cp
3533 instance.save(update_fields=["custom_properties"])
3534
3535 # send_websocket_update offloads async_to_sync to a real OS thread when gevent is active.
3536 channel_uuid = str(instance.channel.uuid)
3537 recording_id = instance.id
3538 task_id = instance.task_id
3539 channel_name = instance.channel.name
3540
3541 try:
3542 from core.utils import send_websocket_update
3543 send_websocket_update('updates', 'update', {
3544 "success": True,
3545 "type": "recording_stopped",
3546 "channel": channel_name,
3547 })
3548 except Exception:
3549 pass
3550
3551 # DVR client teardown and task revocation are deferred to a daemon thread
3552 # because they have occasional slow paths (Redis timeouts, Celery control
3553 # broadcasts) that would otherwise add 5-15 s to the HTTP response time.
3554 def _background_stop():
3555 try:
3556 stopped = _stop_dvr_clients(channel_uuid, recording_id=recording_id)
3557 if stopped:
3558 logger.info(
3559 f"Stopped {stopped} DVR client(s) for channel {channel_uuid} (recording stopped early)"
3560 )
3561 except Exception as e:
3562 logger.debug(f"Unable to stop DVR clients for stopped recording: {e}")
3563
3564 try:
3565 from apps.channels.signals import revoke_task
3566 revoke_task(task_id)
3567 except Exception as e:

Callers

nothing calls this directly

Calls 4

send_websocket_updateFunction · 0.90
getMethod · 0.45
saveMethod · 0.45
startMethod · 0.45

Tested by

no test coverage detected