|
2 | 2 |
|
3 | 3 | namespace App\Http\Controllers\Api; |
4 | 4 |
|
5 | | -use App\Facades\LogoFacade; |
6 | 5 | use App\Facades\PlaylistFacade; |
7 | 6 | use App\Http\Controllers\Controller; |
8 | 7 | use App\Models\Channel; |
|
11 | 10 | use App\Models\StreamProfile; |
12 | 11 | use App\Services\M3uProxyService; |
13 | 12 | use App\Settings\GeneralSettings; |
14 | | -use Carbon\Carbon; |
15 | 13 | use Exception; |
16 | 14 | use Illuminate\Http\Request; |
17 | 15 | use Illuminate\Support\Facades\Log; |
@@ -317,209 +315,4 @@ protected function invalidateStreamCaches(array $data): void |
317 | 315 |
|
318 | 316 | Log::info('Cache invalidated for m3u-proxy event', $data); |
319 | 317 | } |
320 | | - |
321 | | - /** |
322 | | - * Get active streams data |
323 | | - * |
324 | | - * Returns the same structure as M3uProxyStreamMonitor page |
325 | | - */ |
326 | | - public function activeStreams(Request $request, M3uProxyService $apiService) |
327 | | - { |
328 | | - $apiStreams = $apiService->fetchActiveStreams(); |
329 | | - $apiClients = $apiService->fetchActiveClients(); |
330 | | - |
331 | | - // Check for connection errors |
332 | | - if (! $apiStreams['success']) { |
333 | | - return response()->json([ |
334 | | - 'success' => false, |
335 | | - 'error' => $apiStreams['error'] ?? 'Unknown error connecting to m3u-proxy', |
336 | | - ], 500); |
337 | | - } |
338 | | - |
339 | | - if (! $apiClients['success']) { |
340 | | - return response()->json([ |
341 | | - 'success' => false, |
342 | | - 'error' => $apiClients['error'] ?? 'Unknown error connecting to m3u-proxy', |
343 | | - ], 500); |
344 | | - } |
345 | | - |
346 | | - if (empty($apiStreams['streams'])) { |
347 | | - return response()->json([ |
348 | | - 'success' => true, |
349 | | - 'streams' => [], |
350 | | - 'globalStats' => [ |
351 | | - 'total_streams' => 0, |
352 | | - 'active_streams' => 0, |
353 | | - 'total_clients' => 0, |
354 | | - 'total_bandwidth_kbps' => 0, |
355 | | - 'avg_clients_per_stream' => '0.00', |
356 | | - ], |
357 | | - 'systemStats' => [], |
358 | | - ]); |
359 | | - } |
360 | | - |
361 | | - // Group clients by stream_id for easier lookup |
362 | | - $clientsByStream = collect($apiClients['clients'] ?? []) |
363 | | - ->groupBy('stream_id') |
364 | | - ->toArray(); |
365 | | - |
366 | | - $streams = []; |
367 | | - foreach ($apiStreams['streams'] as $stream) { |
368 | | - $streamId = $stream['stream_id']; |
369 | | - $streamClients = $clientsByStream[$streamId] ?? []; |
370 | | - |
371 | | - // Get model information if metadata exists |
372 | | - $model = []; |
373 | | - if (isset($stream['metadata']['type']) && isset($stream['metadata']['id'])) { |
374 | | - $modelType = $stream['metadata']['type']; |
375 | | - $modelId = $stream['metadata']['id']; |
376 | | - $title = null; |
377 | | - $logo = null; |
378 | | - |
379 | | - if ($modelType === 'channel') { |
380 | | - $channel = Channel::find($modelId); |
381 | | - if ($channel) { |
382 | | - $title = $channel->name_custom ?? $channel->name ?? $channel->title; |
383 | | - $logo = LogoFacade::getChannelLogoUrl($channel); |
384 | | - } |
385 | | - } elseif ($modelType === 'episode') { |
386 | | - $episode = Episode::find($modelId); |
387 | | - if ($episode) { |
388 | | - $title = $episode->title; |
389 | | - $logo = LogoFacade::getEpisodeLogoUrl($episode); |
390 | | - } |
391 | | - } |
392 | | - |
393 | | - if ($title || $logo) { |
394 | | - $model = [ |
395 | | - 'title' => $title ?? 'N/A', |
396 | | - 'logo' => $logo, |
397 | | - ]; |
398 | | - } |
399 | | - } |
400 | | - |
401 | | - // Calculate uptime |
402 | | - $startedAt = Carbon::parse($stream['created_at'], 'UTC'); |
403 | | - $uptime = $startedAt->diffForHumans(null, true); |
404 | | - |
405 | | - // Format bytes transferred |
406 | | - $bytesTransferred = $this->formatBytes($stream['total_bytes_served']); |
407 | | - |
408 | | - // Calculate bandwidth (approximate based on bytes and time) |
409 | | - $durationSeconds = $startedAt->diffInSeconds(now()); |
410 | | - $bandwidthKbps = $durationSeconds > 0 |
411 | | - ? round(($stream['total_bytes_served'] * 8) / $durationSeconds / 1000, 2) |
412 | | - : 0; |
413 | | - |
414 | | - // Normalize clients |
415 | | - $clients = array_map(function ($client) { |
416 | | - $connectedAt = Carbon::parse($client['created_at'], 'UTC'); |
417 | | - $lastAccess = Carbon::parse($client['last_access'], 'UTC'); |
418 | | - |
419 | | - // Client is considered active if: |
420 | | - // 1. is_connected is true (from API), OR |
421 | | - // 2. last_access was within the last 30 seconds (more lenient for active streaming) |
422 | | - $isActive = ($client['is_connected'] ?? false) || $lastAccess->diffInSeconds(now()) < 30; |
423 | | - |
424 | | - return [ |
425 | | - 'ip' => $client['ip_address'], |
426 | | - 'username' => $client['username'] ?? null, |
427 | | - 'connected_at' => $connectedAt->format('Y-m-d H:i:s'), |
428 | | - 'duration' => $connectedAt->diffForHumans(null, true), |
429 | | - 'bytes_received' => $this->formatBytes($client['bytes_served']), |
430 | | - 'bandwidth' => 'N/A', // Can calculate if needed |
431 | | - 'is_active' => $isActive, |
432 | | - ]; |
433 | | - }, $streamClients); |
434 | | - |
435 | | - $transcoding = $stream['metadata']['transcoding'] ?? false; |
436 | | - $transcodingFormat = null; |
437 | | - if ($transcoding) { |
438 | | - $profile = StreamProfile::find($stream['metadata']['profile_id'] ?? null); |
439 | | - if ($profile) { |
440 | | - $transcodingFormat = $profile->format === 'm3u8' |
441 | | - ? 'HLS' |
442 | | - : strtoupper($profile->format); |
443 | | - } |
444 | | - } |
445 | | - |
446 | | - $streams[] = [ |
447 | | - 'stream_id' => $streamId, |
448 | | - 'source_url' => $this->truncateUrl($stream['original_url']), |
449 | | - 'current_url' => $stream['current_url'], |
450 | | - 'format' => strtoupper($stream['stream_type']), |
451 | | - 'status' => $stream['is_active'] && $stream['client_count'] > 0 ? 'active' : 'idle', |
452 | | - 'client_count' => $stream['client_count'], |
453 | | - 'bandwidth_kbps' => $bandwidthKbps, |
454 | | - 'bytes_transferred' => $bytesTransferred, |
455 | | - 'uptime' => $uptime, |
456 | | - 'started_at' => $startedAt->format('Y-m-d H:i:s'), |
457 | | - 'process_running' => $stream['is_active'] && $stream['client_count'] > 0, |
458 | | - 'model' => $model, |
459 | | - 'clients' => $clients, |
460 | | - 'has_failover' => $stream['has_failover'], |
461 | | - 'error_count' => $stream['error_count'], |
462 | | - 'segments_served' => $stream['total_segments_served'], |
463 | | - 'transcoding' => $transcoding, |
464 | | - 'transcoding_format' => $transcodingFormat, |
465 | | - // Failover details |
466 | | - 'failover_urls' => $stream['failover_urls'] ?? [], |
467 | | - 'failover_resolver_url' => $stream['failover_resolver_url'] ?? null, |
468 | | - 'current_failover_index' => $stream['current_failover_index'] ?? 0, |
469 | | - 'failover_attempts' => $stream['failover_attempts'] ?? 0, |
470 | | - 'last_failover_time' => isset($stream['last_failover_time']) |
471 | | - ? Carbon::parse($stream['last_failover_time'], 'UTC')->format('Y-m-d H:i:s') |
472 | | - : null, |
473 | | - 'using_failover' => ($stream['current_failover_index'] ?? 0) > 0 || ($stream['failover_attempts'] ?? 0) > 0, |
474 | | - ]; |
475 | | - } |
476 | | - |
477 | | - // Calculate global stats |
478 | | - $totalClients = array_sum(array_map(fn ($s) => $s['client_count'] ?? 0, $streams)); |
479 | | - $totalBandwidth = array_sum(array_map(fn ($s) => $s['bandwidth_kbps'] ?? 0, $streams)); |
480 | | - $activeStreams = count(array_filter($streams, fn ($s) => $s['status'] === 'active')); |
481 | | - |
482 | | - $globalStats = [ |
483 | | - 'total_streams' => count($streams), |
484 | | - 'active_streams' => $activeStreams, |
485 | | - 'total_clients' => $totalClients, |
486 | | - 'total_bandwidth_kbps' => round($totalBandwidth, 2), |
487 | | - 'avg_clients_per_stream' => count($streams) > 0 |
488 | | - ? number_format($totalClients / count($streams), 2) |
489 | | - : '0.00', |
490 | | - ]; |
491 | | - |
492 | | - return response()->json([ |
493 | | - 'success' => true, |
494 | | - 'streams' => $streams, |
495 | | - 'globalStats' => $globalStats, |
496 | | - 'systemStats' => [], // populate if external API provides system metrics |
497 | | - ]); |
498 | | - } |
499 | | - |
500 | | - /** |
501 | | - * Truncate a URL for display |
502 | | - */ |
503 | | - protected function truncateUrl(string $url, int $maxLength = 50): string |
504 | | - { |
505 | | - if (strlen($url) <= $maxLength) { |
506 | | - return $url; |
507 | | - } |
508 | | - |
509 | | - return substr($url, 0, $maxLength - 3).'...'; |
510 | | - } |
511 | | - |
512 | | - /** |
513 | | - * Format bytes into human readable format |
514 | | - */ |
515 | | - protected function formatBytes(int $bytes, int $precision = 2): string |
516 | | - { |
517 | | - $units = ['B', 'KB', 'MB', 'GB', 'TB']; |
518 | | - |
519 | | - for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { |
520 | | - $bytes /= 1024; |
521 | | - } |
522 | | - |
523 | | - return round($bytes, $precision).' '.$units[$i]; |
524 | | - } |
525 | 318 | } |
0 commit comments