Dispatcharr/core/serializers.py
SergeantPanda fd93c0dc3d
Some checks failed
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Has been cancelled
fix(channel management): Implement channel initialization grace period handling to ensure proper state transitions during live stream startup. Channels now honor the configured grace period for buffer filling, promoting to active state when conditions are met. Updated related tests and documentation for clarity. (Fixes #1380)
2026-06-25 14:24:30 -05:00

174 lines
6 KiB
Python

# core/serializers.py
import json
import ipaddress
from rest_framework import serializers
from .models import CoreSettings, UserAgent, StreamProfile, OutputProfile, DVR_SETTINGS_KEY, NETWORK_ACCESS_KEY
class UserAgentSerializer(serializers.ModelSerializer):
class Meta:
model = UserAgent
fields = [
"id",
"name",
"user_agent",
"description",
"is_active",
"created_at",
"updated_at",
]
class StreamProfileSerializer(serializers.ModelSerializer):
class Meta:
model = StreamProfile
fields = [
"id",
"name",
"command",
"parameters",
"is_active",
"user_agent",
"locked",
]
class OutputProfileSerializer(serializers.ModelSerializer):
class Meta:
model = OutputProfile
fields = ["id", "name", "command", "parameters", "is_active", "locked"]
class CoreSettingsSerializer(serializers.ModelSerializer):
class Meta:
model = CoreSettings
fields = "__all__"
def update(self, instance, validated_data):
if instance.key == NETWORK_ACCESS_KEY:
errors = False
invalid = {}
value = validated_data.get("value")
for key, val in value.items():
cidrs = val.split(",")
for cidr in cidrs:
try:
ipaddress.ip_network(cidr)
except:
errors = True
if key not in invalid:
invalid[key] = []
invalid[key].append(cidr)
if errors:
# Perform CIDR validation
raise serializers.ValidationError(
{
"message": "Invalid CIDRs",
"value": invalid,
}
)
# Sanitize series_rules when DVR settings are saved through the
# generic settings API (e.g. Settings page round-trip) to prevent
# corrupted non-dict entries from persisting.
if instance.key == DVR_SETTINGS_KEY:
value = validated_data.get("value")
if isinstance(value, dict) and "series_rules" in value:
rules = value["series_rules"]
value["series_rules"] = (
[r for r in rules if isinstance(r, dict)]
if isinstance(rules, list)
else []
)
result = super().update(instance, validated_data)
# Note: Cache invalidation and notification sync is handled by post_save signal
# in core/signals.py to ensure it happens even if settings are updated elsewhere
return result
class ProxySettingsSerializer(serializers.Serializer):
"""Serializer for proxy settings stored as JSON in CoreSettings"""
buffering_timeout = serializers.IntegerField(min_value=0, max_value=300)
buffering_speed = serializers.FloatField(min_value=0.1, max_value=10.0)
redis_chunk_ttl = serializers.IntegerField(min_value=10, max_value=3600)
channel_shutdown_delay = serializers.IntegerField(min_value=0, max_value=300)
channel_init_grace_period = serializers.IntegerField(min_value=0, max_value=60)
new_client_behind_seconds = serializers.IntegerField(min_value=0, max_value=120, required=False, default=5)
def validate_buffering_timeout(self, value):
if value < 0 or value > 300:
raise serializers.ValidationError("Buffering timeout must be between 0 and 300 seconds")
return value
def validate_buffering_speed(self, value):
if value < 0.1 or value > 10.0:
raise serializers.ValidationError("Buffering speed must be between 0.1 and 10.0")
return value
def validate_redis_chunk_ttl(self, value):
if value < 10 or value > 3600:
raise serializers.ValidationError("Redis chunk TTL must be between 10 and 3600 seconds")
return value
def validate_channel_shutdown_delay(self, value):
if value < 0 or value > 300:
raise serializers.ValidationError("Channel shutdown delay must be between 0 and 300 seconds")
return value
def validate_channel_init_grace_period(self, value):
if value < 0 or value > 60:
raise serializers.ValidationError(
"Channel initialization timeout must be between 0 and 60 seconds"
)
return value
def validate_new_client_behind_seconds(self, value):
if value < 0 or value > 120:
raise serializers.ValidationError("New client buffer must be between 0 and 120 seconds")
return value
class SystemNotificationSerializer(serializers.ModelSerializer):
"""Serializer for system notifications."""
is_dismissed = serializers.SerializerMethodField()
class Meta:
from .models import SystemNotification
model = SystemNotification
fields = [
'id',
'notification_key',
'notification_type',
'priority',
'title',
'message',
'action_data',
'is_active',
'admin_only',
'expires_at',
'created_at',
'is_dismissed',
'source',
]
read_only_fields = ['created_at']
def get_is_dismissed(self, obj):
"""Check if the current user has dismissed this notification."""
request = self.context.get('request')
if request and request.user.is_authenticated:
return obj.dismissals.filter(user=request.user).exists()
return False
class NotificationDismissalSerializer(serializers.ModelSerializer):
"""Serializer for notification dismissals."""
class Meta:
from .models import NotificationDismissal
model = NotificationDismissal
fields = ['id', 'notification', 'dismissed_at', 'action_taken']
read_only_fields = ['dismissed_at']