mirror of
https://github.com/koel/koel
synced 2024-11-24 05:03:05 +00:00
feat(plus): support S3 compatible storages
This commit is contained in:
parent
28af8c0122
commit
b723f3d7c9
43 changed files with 563 additions and 379 deletions
|
@ -104,8 +104,9 @@ class SongBuilder extends Builder
|
|||
: $column;
|
||||
}
|
||||
|
||||
public function hostedOnS3(): static
|
||||
public function storedOnCloud(): static
|
||||
{
|
||||
return $this->where('path', 'LIKE', 's3://%');
|
||||
return $this->where('path', 'LIKE', 's3://%')
|
||||
->orWhere('path', 'LIKE', 'r2://%');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,17 @@
|
|||
namespace App\Factories;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Services\Streamers\DirectStreamerInterface;
|
||||
use App\Services\Streamers\ObjectStorageStreamerInterface;
|
||||
use App\Services\Streamers\LocalStreamerInterface;
|
||||
use App\Services\Streamers\S3CompatibleStreamer;
|
||||
use App\Services\Streamers\StreamerInterface;
|
||||
use App\Services\Streamers\TranscodingStreamerInterface;
|
||||
use App\Services\Streamers\TranscodingStreamer;
|
||||
use App\Services\TranscodingService;
|
||||
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
||||
|
||||
class StreamerFactory
|
||||
{
|
||||
public function __construct(
|
||||
private DirectStreamerInterface $directStreamer,
|
||||
private TranscodingStreamerInterface $transcodingStreamer,
|
||||
private ObjectStorageStreamerInterface $objectStorageStreamer,
|
||||
private TranscodingService $transcodingService
|
||||
) {
|
||||
public function __construct(private TranscodingService $transcodingService)
|
||||
{
|
||||
}
|
||||
|
||||
public function createStreamer(
|
||||
|
@ -25,26 +22,28 @@ class StreamerFactory
|
|||
?int $bitRate = null,
|
||||
float $startTime = 0.0
|
||||
): StreamerInterface {
|
||||
if ($song->s3_params) {
|
||||
$this->objectStorageStreamer->setSong($song);
|
||||
|
||||
return $this->objectStorageStreamer;
|
||||
if ($song->storage_metadata instanceof S3CompatibleMetadata) {
|
||||
return tap(
|
||||
app(S3CompatibleStreamer::class),
|
||||
static fn (S3CompatibleStreamer $streamer) => $streamer->setSong($song)
|
||||
);
|
||||
}
|
||||
|
||||
if ($transcode === null && $this->transcodingService->songShouldBeTranscoded($song)) {
|
||||
$transcode = true;
|
||||
}
|
||||
$transcode ??= $this->transcodingService->songShouldBeTranscoded($song);
|
||||
|
||||
if ($transcode) {
|
||||
$this->transcodingStreamer->setSong($song);
|
||||
$this->transcodingStreamer->setBitRate($bitRate ?: config('koel.streaming.bitrate'));
|
||||
$this->transcodingStreamer->setStartTime($startTime);
|
||||
/** @var TranscodingStreamer $streamer */
|
||||
$streamer = app(TranscodingStreamer::class);
|
||||
$streamer->setSong($song);
|
||||
$streamer->setBitRate($bitRate ?: config('koel.streaming.bitrate'));
|
||||
$streamer->setStartTime($startTime);
|
||||
|
||||
return $this->transcodingStreamer;
|
||||
return $streamer;
|
||||
}
|
||||
|
||||
$this->directStreamer->setSong($song);
|
||||
|
||||
return $this->directStreamer;
|
||||
return tap(
|
||||
app(LocalStreamerInterface::class),
|
||||
static fn (LocalStreamerInterface $streamer) => $streamer->setSong($song)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use App\Http\Resources\SongResource;
|
|||
use App\Models\User;
|
||||
use App\Repositories\AlbumRepository;
|
||||
use App\Repositories\SongRepository;
|
||||
use App\Services\UploadService;
|
||||
use App\Services\SongStorage\SongStorage;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class UploadController extends Controller
|
|||
{
|
||||
/** @param User $user */
|
||||
public function __invoke(
|
||||
UploadService $uploadService,
|
||||
SongStorage $storage,
|
||||
AlbumRepository $albumRepository,
|
||||
SongRepository $songRepository,
|
||||
UploadRequest $request,
|
||||
|
@ -29,7 +29,7 @@ class UploadController extends Controller
|
|||
$this->authorize('upload', User::class);
|
||||
|
||||
try {
|
||||
$song = $songRepository->getOne($uploadService->handleUploadedFile($request->file, $user)->id, $user);
|
||||
$song = $songRepository->getOne($storage->storeUploadedFile($request->file, $user)->id, $user);
|
||||
|
||||
event(new LibraryChanged());
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class DeleteNonExistingRecordsPostSync
|
|||
$paths = $event->results
|
||||
->valid()
|
||||
->map(static fn (ScanResult $result) => $result->path)
|
||||
->merge($this->songRepository->getAllHostedOnS3()->pluck('path'))
|
||||
->merge($this->songRepository->getAllStoredOnCloud()->pluck('path'))
|
||||
->toArray();
|
||||
|
||||
Song::deleteWhereValueNotIn($paths, 'path');
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Builders\SongBuilder;
|
||||
use App\Values\SongStorageMetadata\LocalMetadata;
|
||||
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
||||
use App\Values\SongStorageMetadata\StorageMetadata;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
@ -37,6 +40,7 @@ use Laravel\Scout\Searchable;
|
|||
* @property int $owner_id
|
||||
* @property bool $is_public
|
||||
* @property User $owner
|
||||
* @property-read StorageMetadata $storage_metadata
|
||||
*
|
||||
* // The following are only available for collaborative playlists
|
||||
* @property-read ?string $collaborator_email The email of the user who added the song to the playlist
|
||||
|
@ -143,6 +147,19 @@ class Song extends Model
|
|||
return new Attribute(get: $normalizer, set: $normalizer);
|
||||
}
|
||||
|
||||
protected function storageMetadata(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: function (): StorageMetadata {
|
||||
if (preg_match('/^s3:\\/\\/(.*)\\/(.*)/', $this->path, $matches)) {
|
||||
return S3CompatibleMetadata::make($matches[1], $matches[2]);
|
||||
}
|
||||
|
||||
return LocalMetadata::make($this->path);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function s3Params(): Attribute
|
||||
{
|
||||
return Attribute::get(function (): ?array {
|
||||
|
|
27
app/Providers/SongStorageServiceProvider.php
Normal file
27
app/Providers/SongStorageServiceProvider.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Services\SongStorage\LocalStorage;
|
||||
use App\Services\SongStorage\S3CompatibleStorage;
|
||||
use App\Services\SongStorage\SongStorage;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class SongStorageServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(SongStorage::class, function () {
|
||||
$concrete = match (config('koel.storage_driver')) {
|
||||
's3' => S3CompatibleStorage::class,
|
||||
default => LocalStorage::class,
|
||||
};
|
||||
|
||||
return $this->app->make($concrete);
|
||||
});
|
||||
|
||||
$this->app->when(S3CompatibleStorage::class)
|
||||
->needs('$bucket')
|
||||
->giveConfig('filesystems.disks.s3.bucket');
|
||||
}
|
||||
}
|
|
@ -2,12 +2,8 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Services\Streamers\DirectStreamerInterface;
|
||||
use App\Services\Streamers\ObjectStorageStreamerInterface;
|
||||
use App\Services\Streamers\LocalStreamerInterface;
|
||||
use App\Services\Streamers\PhpStreamer;
|
||||
use App\Services\Streamers\S3Streamer;
|
||||
use App\Services\Streamers\TranscodingStreamer;
|
||||
use App\Services\Streamers\TranscodingStreamerInterface;
|
||||
use App\Services\Streamers\XAccelRedirectStreamer;
|
||||
use App\Services\Streamers\XSendFileStreamer;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
@ -16,15 +12,12 @@ class StreamerServiceProvider extends ServiceProvider
|
|||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(DirectStreamerInterface::class, static function (): DirectStreamerInterface {
|
||||
$this->app->bind(LocalStreamerInterface::class, static function (): LocalStreamerInterface {
|
||||
return match (config('koel.streaming.method')) {
|
||||
'x-sendfile' => new XSendFileStreamer(),
|
||||
'x-accel-redirect' => new XAccelRedirectStreamer(),
|
||||
default => new PhpStreamer(),
|
||||
};
|
||||
});
|
||||
|
||||
$this->app->bind(TranscodingStreamerInterface::class, TranscodingStreamer::class);
|
||||
$this->app->bind(ObjectStorageStreamerInterface::class, S3Streamer::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,15 @@ class SongRepository extends Repository
|
|||
{
|
||||
private const DEFAULT_QUEUE_LIMIT = 500;
|
||||
|
||||
public function getOneByPath(string $path): ?Song
|
||||
public function findOneByPath(string $path): ?Song
|
||||
{
|
||||
return Song::query()->where('path', $path)->first();
|
||||
}
|
||||
|
||||
/** @return Collection|array<Song> */
|
||||
public function getAllHostedOnS3(): Collection
|
||||
public function getAllStoredOnCloud(): Collection
|
||||
{
|
||||
return Song::query()->hostedOnS3()->get();
|
||||
return Song::query()->storedOnCloud()->get();
|
||||
}
|
||||
|
||||
/** @return Collection|array<array-key, Song> */
|
||||
|
|
|
@ -42,7 +42,7 @@ class FileScanner
|
|||
$file = $path instanceof SplFileInfo ? $path : new SplFileInfo($path);
|
||||
|
||||
$this->filePath = $file->getRealPath();
|
||||
$this->song = $this->songRepository->getOneByPath($this->filePath);
|
||||
$this->song = $this->songRepository->findOneByPath($this->filePath);
|
||||
$this->fileModifiedTime = Helper::getModifiedTime($file);
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -134,7 +134,7 @@ class MediaScanner
|
|||
|
||||
private function handleDeletedFileRecord(string $path): void
|
||||
{
|
||||
$song = $this->songRepository->getOneByPath($path);
|
||||
$song = $this->songRepository->findOneByPath($path);
|
||||
|
||||
if ($song) {
|
||||
$song->delete();
|
||||
|
|
|
@ -89,7 +89,7 @@ class S3Service implements ObjectStorageInterface
|
|||
public function deleteSongEntry(string $bucket, string $key): void
|
||||
{
|
||||
$path = Song::getPathFromS3BucketAndKey($bucket, $key);
|
||||
$song = $this->songRepository->getOneByPath($path);
|
||||
$song = $this->songRepository->findOneByPath($path);
|
||||
|
||||
throw_unless((bool) $song, SongPathNotFoundException::create($path));
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
namespace App\Services\SongStorage;
|
||||
|
||||
use App\Exceptions\MediaPathNotSetException;
|
||||
use App\Exceptions\SongUploadFailedException;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\FileScanner;
|
||||
use App\Values\ScanConfiguration;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
@ -14,13 +15,13 @@ use Throwable;
|
|||
|
||||
use function Functional\memoize;
|
||||
|
||||
class UploadService
|
||||
class LocalStorage implements SongStorage
|
||||
{
|
||||
public function __construct(private FileScanner $scanner)
|
||||
{
|
||||
}
|
||||
|
||||
public function handleUploadedFile(UploadedFile $file, User $uploader): Song
|
||||
public function storeUploadedFile(UploadedFile $file, User $uploader): Song
|
||||
{
|
||||
$uploadDirectory = $this->getUploadDirectory($uploader);
|
||||
$targetFileName = $this->getTargetFileName($file, $uploader);
|
||||
|
@ -29,12 +30,11 @@ class UploadService
|
|||
$targetPathName = $uploadDirectory . $targetFileName;
|
||||
|
||||
try {
|
||||
$result = $this->scanner->setFile($targetPathName)->scan(
|
||||
ScanConfiguration::make(
|
||||
$result = $this->scanner->setFile($targetPathName)
|
||||
->scan(ScanConfiguration::make(
|
||||
owner: $uploader,
|
||||
makePublic: $uploader->preferences->makeUploadsPublic
|
||||
)
|
||||
);
|
||||
));
|
||||
} catch (Throwable $e) {
|
||||
File::delete($targetPathName);
|
||||
throw new SongUploadFailedException($e->getMessage());
|
58
app/Services/SongStorage/S3CompatibleStorage.php
Normal file
58
app/Services/SongStorage/S3CompatibleStorage.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\SongStorage;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\FileScanner;
|
||||
use App\Values\ScanConfiguration;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Uid\Ulid;
|
||||
|
||||
class S3CompatibleStorage implements SongStorage
|
||||
{
|
||||
public function __construct(private FileScanner $scanner, private string $bucket)
|
||||
{
|
||||
}
|
||||
|
||||
public function storeUploadedFile(UploadedFile $file, User $uploader): Song
|
||||
{
|
||||
// can't scan the uploaded file directly, as it may cause some misbehavior
|
||||
// instead, we copy the file to the tmp directory and scan it from there
|
||||
$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . Str::uuid();
|
||||
File::makeDirectory($tmpDir);
|
||||
$tmpFile = $file->move($tmpDir, $file->getClientOriginalName());
|
||||
|
||||
return DB::transaction(function () use ($tmpFile, $uploader) {
|
||||
$this->scanner->setFile($tmpFile)
|
||||
->scan(ScanConfiguration::make(
|
||||
owner: $uploader,
|
||||
makePublic: $uploader->preferences->makeUploadsPublic
|
||||
));
|
||||
|
||||
$song = $this->scanner->getSong();
|
||||
$key = $this->generateStorageKey($tmpFile->getFilename(), $uploader);
|
||||
|
||||
Storage::disk('s3')->put($key, $tmpFile->getContent());
|
||||
$song->update(['path' => "s3://$this->bucket/$key"]);
|
||||
|
||||
File::delete($tmpFile->getRealPath());
|
||||
|
||||
return $song;
|
||||
});
|
||||
}
|
||||
|
||||
public function getSongPresignedUrl(Song $song): string
|
||||
{
|
||||
return Storage::disk('s3')->temporaryUrl($song->storage_metadata->getPath(), now()->addHour());
|
||||
}
|
||||
|
||||
private function generateStorageKey(string $filename, User $uploader): string
|
||||
{
|
||||
return sprintf('%s__%s__%s', $uploader->id, Str::lower(Ulid::generate()), $filename);
|
||||
}
|
||||
}
|
12
app/Services/SongStorage/SongStorage.php
Normal file
12
app/Services/SongStorage/SongStorage.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\SongStorage;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
interface SongStorage
|
||||
{
|
||||
public function storeUploadedFile(UploadedFile $file, User $uploader): Song;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
interface DirectStreamerInterface extends StreamerInterface
|
||||
{
|
||||
}
|
7
app/Services/Streamers/LocalStreamerInterface.php
Normal file
7
app/Services/Streamers/LocalStreamerInterface.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
interface LocalStreamerInterface extends StreamerInterface
|
||||
{
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
interface ObjectStorageStreamerInterface extends StreamerInterface
|
||||
{
|
||||
}
|
|
@ -14,7 +14,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
|
||||
use function DaveRandom\Resume\get_request_header;
|
||||
|
||||
class PhpStreamer extends Streamer implements DirectStreamerInterface
|
||||
class PhpStreamer extends Streamer implements LocalStreamerInterface
|
||||
{
|
||||
public function stream(): void
|
||||
{
|
||||
|
|
24
app/Services/Streamers/S3CompatibleStreamer.php
Normal file
24
app/Services/Streamers/S3CompatibleStreamer.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
use App\Services\SongStorage\S3CompatibleStorage;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Routing\Redirector;
|
||||
|
||||
class S3CompatibleStreamer extends Streamer
|
||||
{
|
||||
public function __construct(private S3CompatibleStorage $storage)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream the current song from the Object Storable server.
|
||||
* Actually, we just redirect the request to the object's presigned URL.
|
||||
*/
|
||||
public function stream(): Redirector|RedirectResponse
|
||||
{
|
||||
return redirect($this->storage->getSongPresignedUrl($this->song));
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
use App\Services\S3Service;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Routing\Redirector;
|
||||
|
||||
class S3Streamer extends Streamer implements ObjectStorageStreamerInterface
|
||||
{
|
||||
public function __construct(private S3Service $s3Service)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream the current song through S3.
|
||||
* Actually, we just redirect the request to the S3 object's location.
|
||||
*
|
||||
* @return Redirector|RedirectResponse
|
||||
*
|
||||
*/
|
||||
public function stream() // @phpcs:ignore
|
||||
{
|
||||
// Get and redirect to the actual presigned-url
|
||||
return redirect($this->s3Service->getSongPublicUrl($this->song));
|
||||
}
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
namespace App\Services\Streamers;
|
||||
|
||||
use App\Models\Song;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use App\Values\SongStorageMetadata\LocalMetadata;
|
||||
|
||||
class Streamer
|
||||
class Streamer implements StreamerInterface
|
||||
{
|
||||
protected ?Song $song = null;
|
||||
|
||||
|
@ -21,12 +21,10 @@ class Streamer
|
|||
{
|
||||
$this->song = $song;
|
||||
|
||||
abort_unless($this->song->s3_params || File::exists($this->song->path), 404);
|
||||
|
||||
// Hard code the content type instead of relying on PHP's fileinfo()
|
||||
// or even Symfony's MIMETypeGuesser, since they appear to be wrong sometimes.
|
||||
if (!$this->song->s3_params) {
|
||||
$this->contentType = 'audio/' . pathinfo($this->song->path, PATHINFO_EXTENSION);
|
||||
if ($this->song->storage_metadata instanceof LocalMetadata) {
|
||||
$this->contentType = 'audio/' . pathinfo($this->song->storage_metadata->getPath(), PATHINFO_EXTENSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,4 @@ use App\Models\Song;
|
|||
interface StreamerInterface
|
||||
{
|
||||
public function setSong(Song $song): void;
|
||||
|
||||
public function stream(); // @phpcs:ignore
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
class TranscodingStreamer extends Streamer implements TranscodingStreamerInterface
|
||||
class TranscodingStreamer extends Streamer implements StreamerInterface
|
||||
{
|
||||
/**
|
||||
* Bit rate the stream should be transcoded at.
|
||||
|
@ -39,7 +39,7 @@ class TranscodingStreamer extends Streamer implements TranscodingStreamerInterfa
|
|||
];
|
||||
|
||||
if ($this->startTime) {
|
||||
array_unshift($args, "-ss {$this->startTime}");
|
||||
array_unshift($args, "-ss $this->startTime");
|
||||
}
|
||||
|
||||
passthru("$ffmpeg " . implode(' ', $args));
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
interface TranscodingStreamerInterface extends StreamerInterface
|
||||
{
|
||||
public function setBitRate(int $bitRate): void;
|
||||
|
||||
public function setStartTime(float $startTime): void;
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace App\Services\Streamers;
|
|||
|
||||
use App\Models\Setting;
|
||||
|
||||
class XAccelRedirectStreamer extends Streamer implements DirectStreamerInterface
|
||||
class XAccelRedirectStreamer extends Streamer implements LocalStreamerInterface
|
||||
{
|
||||
/**
|
||||
* Stream the current song using nginx's X-Accel-Redirect.
|
||||
|
@ -18,7 +18,7 @@ class XAccelRedirectStreamer extends Streamer implements DirectStreamerInterface
|
|||
// See nginx.conf.example.
|
||||
header('X-Media-Root: ' . Setting::get('media_path'));
|
||||
header("X-Accel-Redirect: /media/$relativePath");
|
||||
header("Content-Type: {$this->contentType}");
|
||||
header("Content-Type: $this->contentType");
|
||||
header('Content-Disposition: inline; filename="' . basename($this->song->path) . '"');
|
||||
|
||||
exit;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Services\Streamers;
|
||||
|
||||
class XSendFileStreamer extends Streamer implements DirectStreamerInterface
|
||||
class XSendFileStreamer extends Streamer implements LocalStreamerInterface
|
||||
{
|
||||
/**
|
||||
* Stream the current song using Apache's x_sendfile module.
|
||||
|
|
20
app/Values/SongStorageMetadata/LocalMetadata.php
Normal file
20
app/Values/SongStorageMetadata/LocalMetadata.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\SongStorageMetadata;
|
||||
|
||||
final class LocalMetadata implements StorageMetadata
|
||||
{
|
||||
private function __construct(public string $path)
|
||||
{
|
||||
}
|
||||
|
||||
public static function make(string $path): self
|
||||
{
|
||||
return new self($path);
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
7
app/Values/SongStorageMetadata/R2Metadata.php
Normal file
7
app/Values/SongStorageMetadata/R2Metadata.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\SongStorageMetadata;
|
||||
|
||||
final class R2Metadata extends S3CompatibleMetadata
|
||||
{
|
||||
}
|
20
app/Values/SongStorageMetadata/S3CompatibleMetadata.php
Normal file
20
app/Values/SongStorageMetadata/S3CompatibleMetadata.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\SongStorageMetadata;
|
||||
|
||||
class S3CompatibleMetadata implements StorageMetadata
|
||||
{
|
||||
private function __construct(public string $bucket, public string $key)
|
||||
{
|
||||
}
|
||||
|
||||
public static function make(string $bucket, string $key): self
|
||||
{
|
||||
return new static($bucket, $key);
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
}
|
7
app/Values/SongStorageMetadata/S3Metadata.php
Normal file
7
app/Values/SongStorageMetadata/S3Metadata.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\SongStorageMetadata;
|
||||
|
||||
final class S3Metadata extends S3CompatibleMetadata
|
||||
{
|
||||
}
|
8
app/Values/SongStorageMetadata/StorageMetadata.php
Normal file
8
app/Values/SongStorageMetadata/StorageMetadata.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\SongStorageMetadata;
|
||||
|
||||
interface StorageMetadata
|
||||
{
|
||||
public function getPath(): string;
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
"laravel/framework": "^9.0",
|
||||
"james-heinrich/getid3": "^1.9",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"aws/aws-sdk-php-laravel": "^3.1",
|
||||
"pusher/pusher-php-server": "^4.0",
|
||||
"predis/predis": "~1.0",
|
||||
"jackiedo/dotenv-editor": "^2.0",
|
||||
|
@ -36,7 +35,8 @@
|
|||
"nunomaduro/collision": "^6.2",
|
||||
"jwilsson/spotify-web-api-php": "^5.2",
|
||||
"meilisearch/meilisearch-php": "^0.24.0",
|
||||
"http-interop/http-factory-guzzle": "^1.2"
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"league/flysystem-aws-s3-v3": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.0",
|
||||
|
|
478
composer.lock
generated
478
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "310243edd4bc8d4f2184ff38520a52dd",
|
||||
"content-hash": "6a64a8f7d4da75827254d63d4197bd51",
|
||||
"packages": [
|
||||
{
|
||||
"name": "algolia/algoliasearch-client-php",
|
||||
|
@ -82,23 +82,27 @@
|
|||
},
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
"version": "v1.0.2",
|
||||
"version": "v1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/awslabs/aws-crt-php.git",
|
||||
"reference": "3942776a8c99209908ee0b287746263725685732"
|
||||
"reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/3942776a8c99209908ee0b287746263725685732",
|
||||
"reference": "3942776a8c99209908ee0b287746263725685732",
|
||||
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2",
|
||||
"reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35|^5.4.3"
|
||||
"phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -117,7 +121,7 @@
|
|||
}
|
||||
],
|
||||
"description": "AWS Common Runtime for PHP",
|
||||
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||
"homepage": "https://github.com/awslabs/aws-crt-php",
|
||||
"keywords": [
|
||||
"amazon",
|
||||
"aws",
|
||||
|
@ -126,40 +130,42 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/awslabs/aws-crt-php/issues",
|
||||
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.2"
|
||||
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4"
|
||||
},
|
||||
"time": "2021-09-03T22:57:30+00:00"
|
||||
"time": "2023-11-08T00:42:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.231.15",
|
||||
"version": "3.298.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "ba379285d24b609a997bd8b40933d3e0a3826dfb"
|
||||
"reference": "7c7dd6f596e7f7ba22653a503ae76e8e11702028"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ba379285d24b609a997bd8b40933d3e0a3826dfb",
|
||||
"reference": "ba379285d24b609a997bd8b40933d3e0a3826dfb",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7c7dd6f596e7f7ba22653a503ae76e8e11702028",
|
||||
"reference": "7c7dd6f596e7f7ba22653a503ae76e8e11702028",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"aws/aws-crt-php": "^1.0.2",
|
||||
"aws/aws-crt-php": "^1.2.3",
|
||||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-simplexml": "*",
|
||||
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5",
|
||||
"guzzlehttp/promises": "^1.4.0",
|
||||
"guzzlehttp/psr7": "^1.8.5 || ^2.3",
|
||||
"guzzlehttp/promises": "^1.4.0 || ^2.0",
|
||||
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
|
||||
"mtdowling/jmespath.php": "^2.6",
|
||||
"php": ">=5.5"
|
||||
"php": ">=7.2.5",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"andrewsville/php-token-reflection": "^1.4",
|
||||
"aws/aws-php-sns-message-validator": "~1.0",
|
||||
"behat/behat": "~3.0",
|
||||
"composer/composer": "^1.10.22",
|
||||
"dms/phpunit-arraysubset-asserts": "^0.4.0",
|
||||
"doctrine/cache": "~1.4",
|
||||
"ext-dom": "*",
|
||||
"ext-openssl": "*",
|
||||
|
@ -167,10 +173,11 @@
|
|||
"ext-sockets": "*",
|
||||
"nette/neon": "^2.3",
|
||||
"paragonie/random_compat": ">= 2",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.6.3",
|
||||
"phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5",
|
||||
"psr/cache": "^1.0",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"sebastian/comparator": "^1.2.3"
|
||||
"sebastian/comparator": "^1.2.3 || ^4.0",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
|
||||
|
@ -218,84 +225,9 @@
|
|||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.231.15"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.298.1"
|
||||
},
|
||||
"time": "2022-07-27T18:59:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php-laravel",
|
||||
"version": "3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php-laravel.git",
|
||||
"reference": "cfae1e4e770704cf546051c0ba3d480f0031c51f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php-laravel/zipball/cfae1e4e770704cf546051c0ba3d480f0031c51f",
|
||||
"reference": "cfae1e4e770704cf546051c0ba3d480f0031c51f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"aws/aws-sdk-php": "~3.0",
|
||||
"illuminate/support": "^5.1 || ^6.0 || ^7.0 || ^8.0 || ^9.0",
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0",
|
||||
"vlucas/phpdotenv": "^1.0 || ^2.0 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"laravel/framework": "To test the Laravel bindings",
|
||||
"laravel/lumen-framework": "To test the Lumen bindings"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Aws\\Laravel\\AwsServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"AWS": "Aws\\Laravel\\AwsFacade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Aws\\Laravel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Amazon Web Services",
|
||||
"homepage": "http://aws.amazon.com"
|
||||
}
|
||||
],
|
||||
"description": "A simple Laravel 5/6/7/8/9 service provider for including the AWS SDK for PHP.",
|
||||
"homepage": "http://aws.amazon.com/sdkforphp2",
|
||||
"keywords": [
|
||||
"amazon",
|
||||
"aws",
|
||||
"dynamodb",
|
||||
"ec2",
|
||||
"laravel",
|
||||
"laravel 5",
|
||||
"laravel 6",
|
||||
"laravel 7",
|
||||
"laravel 8",
|
||||
"laravel 9",
|
||||
"s3",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/aws/aws-sdk-php-laravel/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php-laravel/tree/3.7.0"
|
||||
},
|
||||
"time": "2022-03-08T22:02:03+00:00"
|
||||
"time": "2024-02-01T19:07:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
@ -1434,22 +1366,22 @@
|
|||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.4.5",
|
||||
"version": "7.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82"
|
||||
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/1dd98b0564cb3f6bd16ce683cb755f94c10fbd82",
|
||||
"reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
|
||||
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/promises": "^1.5",
|
||||
"guzzlehttp/psr7": "^1.9 || ^2.4",
|
||||
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
|
||||
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||
|
@ -1458,10 +1390,11 @@
|
|||
"psr/http-client-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.4.1",
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-curl": "*",
|
||||
"php-http/client-integration-tests": "^3.0",
|
||||
"phpunit/phpunit": "^8.5.5 || ^9.3.5",
|
||||
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
|
||||
"php-http/message-factory": "^1.1",
|
||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
|
||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
|
@ -1471,8 +1404,9 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "7.4-dev"
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1538,7 +1472,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.4.5"
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1554,38 +1488,37 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-20T22:16:13+00:00"
|
||||
"time": "2023-12-03T20:35:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "1.5.1",
|
||||
"version": "2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
|
||||
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
|
||||
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
|
||||
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^4.4 || ^5.1"
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.5-dev"
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
}
|
||||
|
@ -1622,7 +1555,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/promises/issues",
|
||||
"source": "https://github.com/guzzle/promises/tree/1.5.1"
|
||||
"source": "https://github.com/guzzle/promises/tree/2.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1638,26 +1571,26 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-22T20:56:57+00:00"
|
||||
"time": "2023-12-03T20:19:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.4.0",
|
||||
"version": "2.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "13388f00956b1503577598873fffb5ae994b5737"
|
||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/13388f00956b1503577598873fffb5ae994b5737",
|
||||
"reference": "13388f00956b1503577598873fffb5ae994b5737",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"psr/http-message": "^1.1 || ^2.0",
|
||||
"ralouphie/getallheaders": "^3.0"
|
||||
},
|
||||
"provide": {
|
||||
|
@ -1665,17 +1598,18 @@
|
|||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.4.1",
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"http-interop/http-factory-tests": "^0.9",
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.3.10"
|
||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1737,7 +1671,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.4.0"
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.6.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1753,7 +1687,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-20T21:43:11+00:00"
|
||||
"time": "2023-12-03T20:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/uri-template",
|
||||
|
@ -2913,23 +2847,26 @@
|
|||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "3.12.2",
|
||||
"version": "3.23.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "f6377c709d2275ed6feaf63e44be7a7162b0e77f"
|
||||
"reference": "199e1aebbe3e62bd39f4d4fc8c61ce0b3786197e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f6377c709d2275ed6feaf63e44be7a7162b0e77f",
|
||||
"reference": "f6377c709d2275ed6feaf63e44be7a7162b0e77f",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/199e1aebbe3e62bd39f4d4fc8c61ce0b3786197e",
|
||||
"reference": "199e1aebbe3e62bd39f4d4fc8c61ce0b3786197e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/flysystem-local": "^3.0.0",
|
||||
"league/mime-type-detection": "^1.0.0",
|
||||
"php": "^8.0.2"
|
||||
},
|
||||
"conflict": {
|
||||
"async-aws/core": "<1.19.0",
|
||||
"async-aws/s3": "<1.14.0",
|
||||
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
|
||||
"guzzlehttp/guzzle": "<7.0",
|
||||
"guzzlehttp/ringphp": "<1.1.1",
|
||||
|
@ -2937,8 +2874,8 @@
|
|||
"symfony/http-client": "<5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"async-aws/s3": "^1.5",
|
||||
"async-aws/simple-s3": "^1.1",
|
||||
"async-aws/s3": "^1.5 || ^2.0",
|
||||
"async-aws/simple-s3": "^1.1 || ^2.0",
|
||||
"aws/aws-sdk-php": "^3.220.0",
|
||||
"composer/semver": "^3.0",
|
||||
"ext-fileinfo": "*",
|
||||
|
@ -2947,9 +2884,9 @@
|
|||
"friendsofphp/php-cs-fixer": "^3.5",
|
||||
"google/cloud-storage": "^1.23",
|
||||
"microsoft/azure-storage-blob": "^1.1",
|
||||
"phpseclib/phpseclib": "^3.0.14",
|
||||
"phpstan/phpstan": "^0.12.26",
|
||||
"phpunit/phpunit": "^9.5.11",
|
||||
"phpseclib/phpseclib": "^3.0.34",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.5.11|^10.0",
|
||||
"sabre/dav": "^4.3.1"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -2984,7 +2921,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem/tree/3.12.2"
|
||||
"source": "https://github.com/thephpleague/flysystem/tree/3.23.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2994,36 +2931,158 @@
|
|||
{
|
||||
"url": "https://github.com/frankdejonge",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-19T12:02:19+00:00"
|
||||
"time": "2024-01-26T18:42:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/mime-type-detection",
|
||||
"version": "1.11.0",
|
||||
"name": "league/flysystem-aws-s3-v3",
|
||||
"version": "3.23.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
||||
"reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd"
|
||||
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
|
||||
"reference": "97728e7a0d40ec9c6147eb0f4ee4cdc6ff0a8240"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
|
||||
"reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/97728e7a0d40ec9c6147eb0f4ee4cdc6ff0a8240",
|
||||
"reference": "97728e7a0d40ec9c6147eb0f4ee4cdc6ff0a8240",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"aws/aws-sdk-php": "^3.220.0",
|
||||
"league/flysystem": "^3.10.0",
|
||||
"league/mime-type-detection": "^1.0.0",
|
||||
"php": "^8.0.2"
|
||||
},
|
||||
"conflict": {
|
||||
"guzzlehttp/guzzle": "<7.0",
|
||||
"guzzlehttp/ringphp": "<1.1.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Flysystem\\AwsS3V3\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frankdejonge.nl"
|
||||
}
|
||||
],
|
||||
"description": "AWS S3 filesystem adapter for Flysystem.",
|
||||
"keywords": [
|
||||
"Flysystem",
|
||||
"aws",
|
||||
"file",
|
||||
"files",
|
||||
"filesystem",
|
||||
"s3",
|
||||
"storage"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.23.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://ecologi.com/frankdejonge",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/frankdejonge",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-26T18:25:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem-local",
|
||||
"version": "3.23.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem-local.git",
|
||||
"reference": "b884d2bf9b53bb4804a56d2df4902bb51e253f00"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/b884d2bf9b53bb4804a56d2df4902bb51e253f00",
|
||||
"reference": "b884d2bf9b53bb4804a56d2df4902bb51e253f00",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"php": "^7.2 || ^8.0"
|
||||
"league/flysystem": "^3.0.0",
|
||||
"league/mime-type-detection": "^1.0.0",
|
||||
"php": "^8.0.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Flysystem\\Local\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frankdejonge.nl"
|
||||
}
|
||||
],
|
||||
"description": "Local filesystem adapter for Flysystem.",
|
||||
"keywords": [
|
||||
"Flysystem",
|
||||
"file",
|
||||
"files",
|
||||
"filesystem",
|
||||
"local"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem-local/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem-local/tree/3.23.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://ecologi.com/frankdejonge",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/frankdejonge",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-26T18:25:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/mime-type-detection",
|
||||
"version": "1.15.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
||||
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
|
||||
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.2",
|
||||
"phpstan/phpstan": "^0.12.68",
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.3"
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -3044,7 +3103,7 @@
|
|||
"description": "Mime-type detection for Flysystem",
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
|
||||
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0"
|
||||
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3056,7 +3115,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-17T13:12:02+00:00"
|
||||
"time": "2024-01-28T23:22:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lstrojny/functional-php",
|
||||
|
@ -3383,25 +3442,25 @@
|
|||
},
|
||||
{
|
||||
"name": "mtdowling/jmespath.php",
|
||||
"version": "2.6.1",
|
||||
"version": "2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jmespath/jmespath.php.git",
|
||||
"reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb"
|
||||
"reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb",
|
||||
"reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb",
|
||||
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b",
|
||||
"reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.4 || ^7.0 || ^8.0",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"symfony/polyfill-mbstring": "^1.17"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/xdebug-handler": "^1.4 || ^2.0",
|
||||
"phpunit/phpunit": "^4.8.36 || ^7.5.15"
|
||||
"composer/xdebug-handler": "^3.0.3",
|
||||
"phpunit/phpunit": "^8.5.33"
|
||||
},
|
||||
"bin": [
|
||||
"bin/jp.php"
|
||||
|
@ -3409,7 +3468,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.6-dev"
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -3425,6 +3484,11 @@
|
|||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
|
@ -3438,9 +3502,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/jmespath/jmespath.php/issues",
|
||||
"source": "https://github.com/jmespath/jmespath.php/tree/2.6.1"
|
||||
"source": "https://github.com/jmespath/jmespath.php/tree/2.7.0"
|
||||
},
|
||||
"time": "2021-06-14T00:11:39+00:00"
|
||||
"time": "2023-08-25T10:54:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
|
@ -4687,21 +4751,21 @@
|
|||
},
|
||||
{
|
||||
"name": "psr/http-client",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-client.git",
|
||||
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
|
||||
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
|
||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0",
|
||||
"psr/http-message": "^1.0"
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -4721,7 +4785,7 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP clients",
|
||||
|
@ -4733,27 +4797,27 @@
|
|||
"psr-18"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-client/tree/master"
|
||||
"source": "https://github.com/php-fig/http-client"
|
||||
},
|
||||
"time": "2020-06-29T06:28:15+00:00"
|
||||
"time": "2023-09-23T14:17:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"psr/http-message": "^1.0"
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -4773,7 +4837,7 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for PSR-7 HTTP message factories",
|
||||
|
@ -4788,31 +4852,31 @@
|
|||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-factory/tree/master"
|
||||
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
|
||||
},
|
||||
"time": "2019-04-30T12:38:16+00:00"
|
||||
"time": "2023-04-10T20:10:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -4841,9 +4905,9 @@
|
|||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-message/tree/master"
|
||||
"source": "https://github.com/php-fig/http-message/tree/1.1"
|
||||
},
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
"time": "2023-04-04T09:50:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
|
@ -5392,25 +5456,25 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.0.2",
|
||||
"version": "v3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c"
|
||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
|
||||
"reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
|
||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2"
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.0-dev"
|
||||
"dev-main": "3.4-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
|
@ -5439,7 +5503,7 @@
|
|||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5455,7 +5519,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-02T09:55:41+00:00"
|
||||
"time": "2023-05-23T14:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
|
@ -6494,16 +6558,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -6518,7 +6582,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
@ -6557,7 +6621,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6573,7 +6637,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
|
|
|
@ -123,7 +123,6 @@ return [
|
|||
Illuminate\Translation\TranslationServiceProvider::class,
|
||||
Illuminate\Validation\ValidationServiceProvider::class,
|
||||
Illuminate\View\ViewServiceProvider::class,
|
||||
Aws\Laravel\AwsServiceProvider::class,
|
||||
Jackiedo\DotenvEditor\DotenvEditorServiceProvider::class,
|
||||
Intervention\Image\ImageServiceProvider::class,
|
||||
|
||||
|
@ -143,6 +142,7 @@ return [
|
|||
App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\ITunesServiceProvider::class,
|
||||
App\Providers\StreamerServiceProvider::class,
|
||||
App\Providers\SongStorageServiceProvider::class,
|
||||
App\Providers\ObjectStorageServiceProvider::class,
|
||||
App\Providers\MacroProvider::class,
|
||||
App\Providers\LicenseServiceProvider::class,
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Aws\Laravel\AwsServiceProvider;
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| AWS SDK Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The configuration options set in this file will be passed directly to the
|
||||
| `Aws\Sdk` object, from which all client objects are created. The minimum
|
||||
| required options are declared here, but the full set of possible options
|
||||
| are documented at:
|
||||
| http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html
|
||||
|
|
||||
*/
|
||||
'endpoint' => env('AWS_ENDPOINT', 'https://s3.amazonaws.com'),
|
||||
|
||||
'credentials' => [
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
],
|
||||
|
||||
'region' => env('AWS_REGION', 'us-east-1'),
|
||||
'version' => 'latest',
|
||||
'ua_append' => [
|
||||
'L5MOD/' . AwsServiceProvider::VERSION,
|
||||
],
|
||||
];
|
|
@ -62,10 +62,14 @@ return [
|
|||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_KEY'),
|
||||
'secret' => env('AWS_SECRET'),
|
||||
'region' => env('AWS_REGION'),
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_REGION', 'us-east-1'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => false,
|
||||
'throw' => true,
|
||||
],
|
||||
|
||||
'rackspace' => [
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'storage_driver' => env('STORAGE_DRIVER', 'r2'),
|
||||
|
||||
'media_path' => env('MEDIA_PATH'),
|
||||
|
||||
// The *relative* path to the directory to store album covers and thumbnails, *with* a trailing slash.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Tests\Feature\KoelPlus;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Services\Streamers\DirectStreamerInterface;
|
||||
use App\Services\Streamers\LocalStreamerInterface;
|
||||
use App\Services\TokenManager;
|
||||
use App\Values\CompositeToken;
|
||||
use Mockery;
|
||||
|
@ -24,7 +24,7 @@ class SongPlayTest extends PlusTestCase
|
|||
'path' => test_path('songs/blank.mp3'),
|
||||
]);
|
||||
|
||||
$mockStreamer = $this->mock(DirectStreamerInterface::class);
|
||||
$mockStreamer = $this->mock(LocalStreamerInterface::class);
|
||||
|
||||
$mockStreamer->shouldReceive('setSong')->with(
|
||||
Mockery::on(static fn (Song $retrievedSong): bool => $retrievedSong->id === $song->id)
|
||||
|
@ -46,7 +46,7 @@ class SongPlayTest extends PlusTestCase
|
|||
/** @var CompositeToken $token */
|
||||
$token = app(TokenManager::class)->createCompositeToken($song->owner);
|
||||
|
||||
$mockStreamer = $this->mock(DirectStreamerInterface::class);
|
||||
$mockStreamer = $this->mock(LocalStreamerInterface::class);
|
||||
|
||||
$mockStreamer->shouldReceive('setSong')->with(
|
||||
Mockery::on(static fn (Song $retrievedSong): bool => $retrievedSong->id === $song->id)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Services\Streamers\DirectStreamerInterface;
|
||||
use App\Services\Streamers\LocalStreamerInterface;
|
||||
use App\Services\TokenManager;
|
||||
use App\Values\CompositeToken;
|
||||
use Mockery;
|
||||
|
@ -26,7 +26,7 @@ class SongPlayTest extends TestCase
|
|||
'path' => test_path('songs/blank.mp3'),
|
||||
]);
|
||||
|
||||
$mockStreamer = $this->mock(DirectStreamerInterface::class);
|
||||
$mockStreamer = $this->mock(LocalStreamerInterface::class);
|
||||
|
||||
$mockStreamer->shouldReceive('setSong')->with(
|
||||
Mockery::on(static fn (Song $retrievedSong): bool => $retrievedSong->id === $song->id)
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Tests\Integration\Factories;
|
|||
use App\Factories\StreamerFactory;
|
||||
use App\Models\Song;
|
||||
use App\Services\Streamers\PhpStreamer;
|
||||
use App\Services\Streamers\S3Streamer;
|
||||
use App\Services\Streamers\S3CompatibleStreamer;
|
||||
use App\Services\Streamers\TranscodingStreamer;
|
||||
use App\Services\Streamers\XAccelRedirectStreamer;
|
||||
use App\Services\Streamers\XSendFileStreamer;
|
||||
|
@ -33,7 +33,7 @@ class StreamerFactoryTest extends TestCase
|
|||
/** @var Song $song */
|
||||
$song = Song::factory()->make(['path' => 's3://bucket/foo.mp3']);
|
||||
|
||||
self::assertInstanceOf(S3Streamer::class, $this->streamerFactory->createStreamer($song));
|
||||
self::assertInstanceOf(S3CompatibleStreamer::class, $this->streamerFactory->createStreamer($song));
|
||||
}
|
||||
|
||||
public function testCreateTranscodingStreamerIfSupported(): void
|
||||
|
|
|
@ -21,6 +21,6 @@ class SongRepositoryTest extends TestCase
|
|||
{
|
||||
/** @var Song $song */
|
||||
$song = Song::factory()->create(['path' => 'foo']);
|
||||
self::assertSame($song->id, $this->songRepository->getOneByPath('foo')->id);
|
||||
self::assertSame($song->id, $this->songRepository->findOneByPath('foo')->id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Integration\Services;
|
||||
namespace Tests\Integration\Services\FileStorage;
|
||||
|
||||
use App\Exceptions\MediaPathNotSetException;
|
||||
use App\Exceptions\SongUploadFailedException;
|
||||
use App\Models\Setting;
|
||||
use App\Services\UploadService;
|
||||
use App\Services\SongStorage\LocalStorage;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Mockery;
|
||||
use Tests\TestCase;
|
||||
|
@ -13,15 +13,15 @@ use Tests\TestCase;
|
|||
use function Tests\create_user;
|
||||
use function Tests\test_path;
|
||||
|
||||
class UploadServiceTest extends TestCase
|
||||
class LocalStorageTest extends TestCase
|
||||
{
|
||||
private UploadService $service;
|
||||
private LocalStorage $service;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->service = app(UploadService::class);
|
||||
$this->service = app(LocalStorage::class);
|
||||
}
|
||||
|
||||
public function testHandleUploadedFileWithMediaPathNotSet(): void
|
||||
|
@ -29,7 +29,7 @@ class UploadServiceTest extends TestCase
|
|||
Setting::set('media_path');
|
||||
|
||||
self::expectException(MediaPathNotSetException::class);
|
||||
$this->service->handleUploadedFile(Mockery::mock(UploadedFile::class), create_user());
|
||||
$this->service->storeUploadedFile(Mockery::mock(UploadedFile::class), create_user());
|
||||
}
|
||||
|
||||
public function testHandleUploadedFileFails(): void
|
||||
|
@ -37,7 +37,7 @@ class UploadServiceTest extends TestCase
|
|||
Setting::set('media_path', public_path('sandbox/media'));
|
||||
|
||||
self::expectException(SongUploadFailedException::class);
|
||||
$this->service->handleUploadedFile(UploadedFile::fake()->create('fake.mp3'), create_user());
|
||||
$this->service->storeUploadedFile(UploadedFile::fake()->create('fake.mp3'), create_user());
|
||||
}
|
||||
|
||||
public function testHandleUploadedFile(): void
|
||||
|
@ -45,7 +45,7 @@ class UploadServiceTest extends TestCase
|
|||
Setting::set('media_path', public_path('sandbox/media'));
|
||||
$user = create_user();
|
||||
|
||||
$song = $this->service->handleUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
$song = $this->service->storeUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
|
||||
self::assertSame($song->owner_id, $user->id);
|
||||
self::assertSame(public_path("sandbox/media/__KOEL_UPLOADS_\${$user->id}__/full.mp3"), $song->path);
|
||||
|
@ -58,12 +58,12 @@ class UploadServiceTest extends TestCase
|
|||
$user->save();
|
||||
|
||||
Setting::set('media_path', public_path('sandbox/media'));
|
||||
$song = $this->service->handleUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
$song = $this->service->storeUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
self::assertTrue($song->is_public);
|
||||
|
||||
$user->preferences->makeUploadsPublic = false;
|
||||
$user->save();
|
||||
$privateSongs = $this->service->handleUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
$privateSongs = $this->service->storeUploadedFile(UploadedFile::fromFile(test_path('songs/full.mp3')), $user); //@phpstan-ignore-line
|
||||
self::assertFalse($privateSongs->is_public);
|
||||
}
|
||||
}
|
|
@ -129,7 +129,7 @@ class S3ServiceTest extends TestCase
|
|||
'path' => 's3://foo/bar',
|
||||
]);
|
||||
|
||||
$this->songRepository->shouldReceive('getOneByPath')
|
||||
$this->songRepository->shouldReceive('findOneByPath')
|
||||
->with('s3://foo/bar')
|
||||
->once()
|
||||
->andReturn($song);
|
||||
|
|
Loading…
Reference in a new issue