myiptv / app /Http /Controllers /VideoController.php
ken1402's picture
Upload 73 files
8baf129 verified
Raw
History Blame Contribute Delete
4.33 kB
<?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'
]);
}
}