2024-02-24 07:28:49 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Services\Streamer;
|
|
|
|
|
2024-04-18 17:20:14 +00:00
|
|
|
use App\Enums\SongStorageType;
|
2024-02-24 07:28:49 +00:00
|
|
|
use App\Exceptions\KoelPlusRequiredException;
|
|
|
|
use App\Models\Song;
|
|
|
|
use App\Services\Streamer\Adapters\DropboxStreamerAdapter;
|
|
|
|
use App\Services\Streamer\Adapters\LocalStreamerAdapter;
|
|
|
|
use App\Services\Streamer\Adapters\S3CompatibleStreamerAdapter;
|
|
|
|
use App\Services\Streamer\Adapters\StreamerAdapter;
|
|
|
|
use App\Services\Streamer\Adapters\TranscodingStreamerAdapter;
|
|
|
|
use Illuminate\Support\Arr;
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
use Illuminate\Support\Str;
|
|
|
|
|
|
|
|
class Streamer
|
|
|
|
{
|
|
|
|
private StreamerAdapter $adapter;
|
|
|
|
|
2024-04-18 14:36:28 +00:00
|
|
|
public function __construct(
|
|
|
|
private readonly Song $song,
|
|
|
|
?StreamerAdapter $adapter = null,
|
|
|
|
private readonly array $config = []
|
|
|
|
) {
|
2024-02-24 07:28:49 +00:00
|
|
|
// Turn off error reporting to make sure our stream isn't interfered.
|
|
|
|
@error_reporting(0);
|
|
|
|
|
|
|
|
$this->adapter = $adapter ?? $this->resolveAdapter();
|
|
|
|
}
|
|
|
|
|
|
|
|
private function resolveAdapter(): StreamerAdapter
|
|
|
|
{
|
2024-04-18 17:20:14 +00:00
|
|
|
throw_unless($this->song->storage->supported(), KoelPlusRequiredException::class);
|
2024-02-24 07:28:49 +00:00
|
|
|
|
|
|
|
if ($this->shouldTranscode()) {
|
|
|
|
return app(TranscodingStreamerAdapter::class);
|
|
|
|
}
|
|
|
|
|
|
|
|
return match ($this->song->storage) {
|
2024-04-18 17:20:14 +00:00
|
|
|
SongStorageType::LOCAL => app(LocalStreamerAdapter::class),
|
|
|
|
SongStorageType::S3, SongStorageType::S3_LAMBDA => app(S3CompatibleStreamerAdapter::class),
|
|
|
|
SongStorageType::DROPBOX => app(DropboxStreamerAdapter::class),
|
2024-02-24 07:28:49 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public function stream(): mixed
|
|
|
|
{
|
|
|
|
return $this->adapter->stream($this->song, $this->config);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function shouldTranscode(): bool
|
|
|
|
{
|
|
|
|
// We only transcode local files. "Remote" transcoding (e.g., from Dropbox) is not supported.
|
2024-04-18 17:20:14 +00:00
|
|
|
if ($this->song->storage !== SongStorageType::LOCAL) {
|
2024-02-24 07:28:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Arr::get($this->config, 'transcode', false)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-18 17:20:14 +00:00
|
|
|
return Str::endsWith(File::mimeType($this->song->storage_metadata->getPath()), 'flac')
|
2024-03-15 12:25:01 +00:00
|
|
|
&& config('koel.streaming.transcode_flac')
|
|
|
|
&& is_executable(config('koel.streaming.ffmpeg_path'));
|
2024-02-24 07:28:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getAdapter(): StreamerAdapter
|
|
|
|
{
|
|
|
|
return $this->adapter;
|
|
|
|
}
|
|
|
|
}
|