File size: 4,325 Bytes
8baf129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php

namespace App\Http\Controllers;

use App\Models\Video;
use App\Services\VideoImporter;
use App\Services\HLS\HLSConverter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class VideoController extends Controller
{
    protected $importer;
    protected $hlsConverter;

    public function __construct(VideoImporter $importer, HLSConverter $hlsConverter)
    {
        $this->importer = $importer;
        $this->hlsConverter = $hlsConverter;
    }

    // === IMPORT VIDEO + HLS ===
    public function import(Request $request)
    {
        $this->validate($request, [
            'import_link' => 'required|url',
            'import_title' => 'nullable|string|max:150',
            'enable_hls' => 'nullable|boolean',
            'hls_quality' => 'nullable|array|min:1|max:3',
            'hls_quality.*' => 'in:1080,720,480'
        ]);

        try {
            $result = $this->importer->import(
                $request->input('import_link'),
                $request->input('import_title', ''),
                (bool) $request->input('enable_hls', false),
                $request->input('hls_quality', ['720'])
            );

            return response()->json([
                'status' => 'success',
                'data' => $result
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'error',
                'message' => $e->getMessage()
            ], 500);
        }
    }

    // === STREAM HLS (master.m3u8, playlist.m3u8, .ts, .chunk) ===
    public function streamHls($folder, $file = 'master.m3u8')
    {
        $path = public_path("hls/{$folder}/{$file}");

        if (!file_exists($path)) {
            return response()->json(['error' => 'File not found'], 404);
        }

        $ext = pathinfo($path, PATHINFO_EXTENSION);

        // Xử lý .m3u8 → rewrite URL .ts
        if ($ext === 'm3u8') {
            $content = file_get_contents($path);
            $baseUrl = url("/api/hls/{$folder}");

            // Thay thế các segment .ts, .chunk hoặc .m4s thành full URL
            $content = preg_replace(
                '/(^\s*)(?!#)([\w\-\.%]+\.(ts|chunk|m4s))/m',
                "$1{$baseUrl}/$2",
                $content
            );

            return response($content, 200, [
                'Content-Type' => 'application/vnd.apple.mpegurl',
                'Access-Control-Allow-Origin' => '*',
                'Access-Control-Allow-Methods' => 'GET, OPTIONS',
                'Access-Control-Allow-Headers' => 'Range',
                'Cache-Control' => 'no-cache',
            ]);
        }

        // Xử lý .ts, .chunk, .m4s
        $mime = in_array($ext, ['ts', 'chunk']) ? 'video/mp2t' : 'video/mp4';

        $response = new BinaryFileResponse($path);
        $response->headers->set('Content-Type', $mime);
        $response->headers->set('Access-Control-Allow-Origin', '*');
        $response->headers->set('Accept-Ranges', 'bytes');
        $response->headers->set('Cache-Control', 'no-cache');

        return $response;
    }

    // === DANH SÁCH VIDEO ===
    public function index(Request $request)
    {
        $perPage = $request->input('per_page', 15);
        $videos = Video::orderBy('created_at', 'desc')->paginate($perPage);

        return response()->json($videos);
    }

    public function show($id)
    {
        $video = Video::findOrFail($id);
        return response()->json($video);
    }

    // === XÓA VIDEO + HLS FILES ===
    public function destroy($id)
    {
        $video = Video::findOrFail($id);

        // Xóa file gốc
        if ($video->path && file_exists($video->path)) {
            @unlink($video->path);
        }

        // Xóa thumbnail
        if ($video->thumbnail && file_exists(storage_path('app/' . $video->thumbnail))) {
            @unlink(storage_path('app/' . $video->thumbnail));
        }

        // Xóa HLS files
        if ($video->hls_enabled && $video->hls_master_playlist) {
            $this->hlsConverter->deleteHLSFiles($video->hls_master_playlist);
        }

        $video->delete();

        return response()->json([
            'status' => 'success',
            'message' => 'Đã xóa video thành công'
        ]);
    }
}