-
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathHLSService.php
More file actions
110 lines (93 loc) · 4.31 KB
/
HLSService.php
File metadata and controls
110 lines (93 loc) · 4.31 KB
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
<?php
declare(strict_types=1);
namespace AchyutN\LaravelHLS\Services;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use ProtoneMedia\LaravelFFMpeg\Support\FFMpeg;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Throwable;
class HLSService
{
public function getKey(string $model, int|string $id, string $key): Response
{
$resolvedModel = $this->resolveModel($model)->query()->findOrFail($id);
$path = "{$resolvedModel->getHlsPath()}/{$resolvedModel->getHLSSecretsOutputPath()}/{$key}";
if (! Storage::disk($resolvedModel->getSecretsDisk())->exists($path)) {
abort(404);
}
return response(Storage::disk($resolvedModel->getSecretsDisk())->get($path), 200, [
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'inline; filename="'.$key.'"',
]);
}
public function getSegment(string $model, int|string $id, string $filename): RedirectResponse|StreamedResponse
{
$resolvedModel = $this->resolveModel($model)->query()->findOrFail($id);
$path = "{$resolvedModel->getHlsPath()}/{$resolvedModel->getHLSOutputPath()}/{$filename}";
if (! Storage::disk($resolvedModel->getHlsDisk())->exists($path)) {
abort(404);
}
// Use the most efficient method based on the storage driver.
return $this->serveFileFromDisk(Storage::disk($resolvedModel->getHlsDisk()), $path);
}
public function getPlaylist(string $model, int|string $id, string $playlist = 'playlist.m3u8'): \ProtoneMedia\LaravelFFMpeg\Http\DynamicHLSPlaylist
{
$resolvedModel = $this->resolveModel($model)->query()->findOrFail($id);
$path = "{$resolvedModel->getHlsPath()}/{$resolvedModel->getHLSOutputPath()}/{$playlist}";
if (! Storage::disk($resolvedModel->getHlsDisk())->exists($path)) {
abort(404);
}
return FFMpeg::dynamicHLSPlaylist($resolvedModel->getHlsDisk())
->fromDisk($resolvedModel->getHlsDisk())
->open($path)
->setKeyUrlResolver(fn ($key) => URL::signedRoute(
'hls.key',
['model' => $model, 'id' => $id, 'key' => $key]
))
->setMediaUrlResolver(fn ($filename) => URL::signedRoute(
'hls.segment',
['model' => $model, 'id' => $id, 'filename' => $filename]
))
->setPlaylistUrlResolver(fn ($filename) => URL::signedRoute(
'hls.playlist',
['model' => $model, 'id' => $id, 'playlist' => $filename]
));
}
private function resolveModel(string $type): Model
{
try {
return app(config('hls.model_aliases')[$type]);
} catch (Throwable $e) {
Log::error("Failed to resolve model for type [{$type}]: ".$e->getMessage());
abort(404, "Unknown model type [{$type}]");
}
}
/**
* Intelligently serves a file from a disk, using the most efficient method.
*
* - For S3: Redirects to a temporary signed URL (for private files) or a public URL.
* - For Local: Streams the file directly.
*/
private function serveFileFromDisk(Filesystem $disk, string $path): StreamedResponse|RedirectResponse
{
$adapter = $disk->getAdapter();
// Check if the driver is S3 or another cloud service that supports temporary URLs.
if (method_exists($adapter, 'getTemporaryUrl')) {
// For private files, generate a temporary signed URL to offload the download to S3.
// This is the most performant and scalable option.
// The visibility check is a good practice, though temporaryUrl works for public files too.
if ($disk->getVisibility($path) === 'private') {
return redirect($disk->temporaryUrl($path, now()->addMinutes(10)));
}
// For public files, just redirect to the permanent public URL.
return redirect($disk->url($path));
}
// For local storage or other drivers, fall back to a standard streamed response.
return $disk->response($path);
}
}