diff --git a/app/Factories/StreamerFactory.php b/app/Factories/StreamerFactory.php new file mode 100644 index 00000000..1a3dca16 --- /dev/null +++ b/app/Factories/StreamerFactory.php @@ -0,0 +1,62 @@ +directStreamer = $directStreamer; + $this->transcodingStreamer = $transcodingStreamer; + $this->objectStorageStreamer = $objectStorageStreamer; + } + + /** + * @param Song $song + * + * @param boolean|null $transcode + * @param int|null $bitRate + * @param int $startTime + * + * @return StreamerInterface + */ + public function createStreamer(Song $song, $transcode = null, $bitRate = null, $startTime = 0) + { + if ($song->s3_params) { + $this->objectStorageStreamer->setSong($song); + + return $this->objectStorageStreamer; + } + + // If `transcode` parameter isn't passed, the default is to only transcode FLAC. + if ($transcode === null && ends_with(mime_content_type($song->path), 'flac')) { + $transcode = true; + } + + if ($transcode) { + $this->transcodingStreamer->setSong($song); + $this->transcodingStreamer->setBitRate($bitRate ?: config('koel.streaming.bitrate')); + $this->transcodingStreamer->setStartTime($startTime); + + return $this->transcodingStreamer; + } + + $this->directStreamer->setSong($song); + + return $this->directStreamer; + } +} diff --git a/app/Http/Controllers/API/SongController.php b/app/Http/Controllers/API/SongController.php index 1ec702ff..54da7646 100644 --- a/app/Http/Controllers/API/SongController.php +++ b/app/Http/Controllers/API/SongController.php @@ -2,15 +2,11 @@ namespace App\Http\Controllers\API; +use App\Factories\StreamerFactory; use App\Http\Requests\API\SongPlayRequest; use App\Http\Requests\API\SongUpdateRequest; use App\Models\Song; use App\Services\MediaInformationService; -use App\Services\Streamers\PHPStreamer; -use App\Services\Streamers\S3Streamer; -use App\Services\Streamers\TranscodingStreamer; -use App\Services\Streamers\XAccelRedirectStreamer; -use App\Services\Streamers\XSendFileStreamer; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Routing\Redirector; @@ -18,10 +14,12 @@ use Illuminate\Routing\Redirector; class SongController extends Controller { private $mediaInformationService; + private $streamerFactory; - public function __construct(MediaInformationService $mediaInformationService) + public function __construct(MediaInformationService $mediaInformationService, StreamerFactory $streamerFactory) { $this->mediaInformationService = $mediaInformationService; + $this->streamerFactory = $streamerFactory; } /** @@ -40,38 +38,9 @@ class SongController extends Controller */ public function play(SongPlayRequest $request, Song $song, $transcode = null, $bitRate = null) { - if ($song->s3_params) { - return (new S3Streamer($song))->stream(); - } - - // If `transcode` parameter isn't passed, the default is to only transcode FLAC. - if ($transcode === null && ends_with(mime_content_type($song->path), 'flac')) { - $transcode = true; - } - - $streamer = null; - - if ($transcode) { - $streamer = new TranscodingStreamer( - $song, - $bitRate ?: config('koel.streaming.bitrate'), - floatval($request->time) - ); - } else { - switch (config('koel.streaming.method')) { - case 'x-sendfile': - $streamer = new XSendFileStreamer($song); - break; - case 'x-accel-redirect': - $streamer = new XAccelRedirectStreamer($song); - break; - default: - $streamer = new PHPStreamer($song); - break; - } - } - - $streamer->stream(); + return $this->streamerFactory + ->createStreamer($song, $transcode, $bitRate, floatval($request->time)) + ->stream(); } /** diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 9371a0db..0e23f1e3 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,11 +2,13 @@ namespace App\Providers; +use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider; use DB; use Illuminate\Database\SQLiteConnection; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Validator; use Illuminate\Support\ServiceProvider; +use Laravel\Tinker\TinkerServiceProvider; class AppServiceProvider extends ServiceProvider { @@ -39,8 +41,8 @@ class AppServiceProvider extends ServiceProvider public function register() { if (!$this->app->environment('production')) { - $this->app->register('Laravel\Tinker\TinkerServiceProvider'); - $this->app->register('Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider'); + $this->app->register(TinkerServiceProvider::class); + $this->app->register(IdeHelperServiceProvider::class); } } } diff --git a/app/Providers/StreamerServiceProvider.php b/app/Providers/StreamerServiceProvider.php new file mode 100644 index 00000000..68298e46 --- /dev/null +++ b/app/Providers/StreamerServiceProvider.php @@ -0,0 +1,41 @@ +app->when(StreamerFactory::class) + ->needs(DirectStreamerInterface::class) + ->give(static function () { + switch (config('koel.streaming.method')) { + case 'x-sendfile': + return new XSendFileStreamer(); + case 'x-accel-redirect': + return new XAccelRedirectStreamer(); + default: + return new PHPStreamer(); + } + }); + + $this->app->when(StreamerFactory::class) + ->needs(TranscodingStreamerInterface::class) + ->give(TranscodingStreamer::class); + + $this->app->when(StreamerFactory::class) + ->needs(ObjectStorageStreamerInterface::class) + ->give(S3Streamer::class); + } +} diff --git a/app/Services/Streamers/DirectStreamerInterface.php b/app/Services/Streamers/DirectStreamerInterface.php new file mode 100644 index 00000000..a0d6fc91 --- /dev/null +++ b/app/Services/Streamers/DirectStreamerInterface.php @@ -0,0 +1,7 @@ +song = $song; @@ -29,9 +30,8 @@ class Streamer // Hard code the content type instead of relying on PHP's fileinfo() // or even Symfony's MIMETypeGuesser, since they appear to be wrong sometimes. - $this->contentType = 'audio/'.pathinfo($this->song->path, PATHINFO_EXTENSION); - - // Turn off error reporting to make sure our stream isn't interfered. - @error_reporting(0); + if (!$this->song->s3_params) { + $this->contentType = 'audio/'.pathinfo($this->song->path, PATHINFO_EXTENSION); + } } } diff --git a/app/Services/Streamers/StreamerInterface.php b/app/Services/Streamers/StreamerInterface.php index 02e5207b..c040e804 100644 --- a/app/Services/Streamers/StreamerInterface.php +++ b/app/Services/Streamers/StreamerInterface.php @@ -2,10 +2,10 @@ namespace App\Services\Streamers; +use App\Models\Song; + interface StreamerInterface { - /** - * Stream the current song. - */ + public function setSong(Song $song); public function stream(); } diff --git a/app/Services/Streamers/TranscodingStreamer.php b/app/Services/Streamers/TranscodingStreamer.php index 93febbe6..8b96b7bf 100644 --- a/app/Services/Streamers/TranscodingStreamer.php +++ b/app/Services/Streamers/TranscodingStreamer.php @@ -2,9 +2,7 @@ namespace App\Services\Streamers; -use App\Models\Song; - -class TranscodingStreamer extends Streamer implements StreamerInterface +class TranscodingStreamer extends Streamer implements TranscodingStreamerInterface { /** * Bit rate the stream should be transcoded at. @@ -20,13 +18,6 @@ class TranscodingStreamer extends Streamer implements StreamerInterface */ private $startTime; - public function __construct(Song $song, $bitRate, $startTime = 0) - { - parent::__construct($song); - $this->bitRate = $bitRate; - $this->startTime = $startTime; - } - /** * On-the-fly stream the current song while transcoding. */ @@ -55,4 +46,14 @@ class TranscodingStreamer extends Streamer implements StreamerInterface passthru("$ffmpeg ".implode($args, ' ')); } + + public function setBitRate($bitRate) + { + $this->bitRate = $bitRate; + } + + public function setStartTime($startTime) + { + $this->startTime = $startTime; + } } diff --git a/app/Services/Streamers/TranscodingStreamerInterface.php b/app/Services/Streamers/TranscodingStreamerInterface.php new file mode 100644 index 00000000..a95c0b83 --- /dev/null +++ b/app/Services/Streamers/TranscodingStreamerInterface.php @@ -0,0 +1,9 @@ +