Dispatcharr/apps/ffmpeg/views.py

75 lines
2.5 KiB
Python

import os
import redis
import subprocess
from django.conf import settings
from django.http import (
StreamingHttpResponse,
HttpResponseServerError,
FileResponse,
Http404,
)
from django.db.models import F
from apps.channels.models import Channel, Stream
# Configure Redis
redis_host = os.environ.get("REDIS_HOST", "redis")
redis_port = int(os.environ.get("REDIS_PORT", 6379))
redis_db = int(os.environ.get("REDIS_DB", 0))
redis_client = redis.Redis(host=redis_host, port=redis_port, db=redis_db)
def serve_hls_segment(request, stream_id, filename):
# Remove any trailing slashes from the filename. / caused problems.
filename = filename.rstrip('/')
# Construct the file path (e.g., /tmp/hls_4/segment_001.ts)
file_path = os.path.join('/tmp', f'hls_{stream_id}', filename)
if os.path.exists(file_path):
return FileResponse(open(file_path, 'rb'), content_type='video/MP2T')
else:
raise Http404("Segment not found")
def stream_view(request, stream_id):
try:
channel = Channel.objects.get(id=stream_id)
if not channel.streams.exists():
return HttpResponseServerError("No stream found for this channel.")
# Pick the first available stream and get its actual model instance.
stream = channel.streams.first()
# Use the custom URL if available; otherwise, the regular URL.
input_url = stream.custom_url or stream.url
# Increment the viewer count atomically.
Stream.objects.filter(id=stream.id).update(current_viewers=F('current_viewers') + 1)
ffmpeg_cmd = [
"ffmpeg",
"-i", input_url,
"-c:v", "copy",
"-c:a", "copy",
"-f", "mpegts",
"-" # output to stdout
]
process = subprocess.Popen(
ffmpeg_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
except Exception as e:
return HttpResponseServerError(f"Error starting stream: {e}")
def stream_generator(process, stream):
try:
while True:
chunk = process.stdout.read(8192)
if not chunk:
break
yield chunk
finally:
# Decrement the viewer count when the stream finishes or the connection closes.
Stream.objects.filter(id=stream.id).update(current_viewers=F('current_viewers') - 1)
return StreamingHttpResponse(
stream_generator(process, stream),
content_type="video/MP2T"
)