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

Function stream_vod

apps/proxy/vod_proxy/views.py:390–630  ·  view source on GitHub ↗

Stream VOD content (movies or series episodes) with session-based connection reuse Args: content_type: 'movie', 'series', or 'episode' content_id: ID of the content session_id: Optional session ID from URL path (for persistent connections) profile_id: Option

(request, content_type, content_id, session_id=None, profile_id=None, user=None)

Source from the content-addressed store, hash-verified

388@authentication_classes([JWTAuthentication, ApiKeyAuthentication, QueryParamJWTAuthentication])
389@permission_classes([AllowAny])
390def stream_vod(request, content_type, content_id, session_id=None, profile_id=None, user=None):
391 """
392 Stream VOD content (movies or series episodes) with session-based connection reuse
393
394 Args:
395 content_type: 'movie', 'series', or 'episode'
396 content_id: ID of the content
397 session_id: Optional session ID from URL path (for persistent connections)
398 profile_id: Optional M3U profile ID for authentication
399 """
400 if not network_access_allowed(request, "STREAMS"):
401 return JsonResponse({"error": "Forbidden"}, status=403)
402 if user is None and hasattr(request, "user") and request.user.is_authenticated:
403 user = request.user
404 logger.info(f"[VOD-REQUEST] Starting VOD stream request: {content_type}/{content_id}, session: {session_id}, profile: {profile_id}")
405 logger.info(f"[VOD-REQUEST] Full request path: {request.get_full_path()}")
406 logger.info(f"[VOD-REQUEST] Request method: {request.method}")
407 logger.info(f"[VOD-REQUEST] Request headers: {dict(request.headers)}")
408
409 try:
410 client_ip, client_user_agent = get_client_info(request)
411
412 # Extract timeshift parameters from query string
413 # Support multiple timeshift parameter formats
414 utc_start = request.GET.get('utc_start') or request.GET.get('start') or request.GET.get('playliststart')
415 utc_end = request.GET.get('utc_end') or request.GET.get('end') or request.GET.get('playlistend')
416 offset = request.GET.get('offset') or request.GET.get('seek') or request.GET.get('t')
417
418 # VLC specific timeshift parameters
419 if not utc_start and not offset:
420 # Check for VLC-style timestamp parameters
421 if 'timestamp' in request.GET:
422 offset = request.GET.get('timestamp')
423 elif 'time' in request.GET:
424 offset = request.GET.get('time')
425
426 # Session ID now comes from URL path parameter
427 # Remove legacy query parameter extraction since we're using path-based routing
428
429 # Extract Range header for seeking support
430 range_header = request.META.get('HTTP_RANGE')
431
432 logger.info(f"[VOD-TIMESHIFT] Timeshift params - utc_start: {utc_start}, utc_end: {utc_end}, offset: {offset}")
433 logger.info(f"[VOD-SESSION] Session ID: {session_id}")
434
435 # Log all query parameters for debugging
436 if request.GET:
437 logger.debug(f"[VOD-PARAMS] All query params: {dict(request.GET)}")
438
439 if range_header:
440 logger.info(f"[VOD-RANGE] Range header: {range_header}")
441
442 # Parse the range to understand what position VLC is seeking to
443 try:
444 if 'bytes=' in range_header:
445 range_part = range_header.replace('bytes=', '')
446 if '-' in range_part:
447 start_byte, end_byte = range_part.split('-', 1)

Calls 14

network_access_allowedFunction · 0.90
check_user_stream_limitsFunction · 0.90
get_client_infoFunction · 0.85
_get_m3u_profileFunction · 0.85
_transform_urlFunction · 0.85
get_clientMethod · 0.80
getMethod · 0.45
setMethod · 0.45
existsMethod · 0.45