mirror of
https://github.com/koel/koel
synced 2024-11-10 14:44:13 +00:00
feat(plus): support Dropbox
This commit is contained in:
parent
833774e20a
commit
06761b7917
16 changed files with 391 additions and 58 deletions
|
@ -3,11 +3,13 @@
|
||||||
namespace App\Factories;
|
namespace App\Factories;
|
||||||
|
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
|
use App\Services\Streamers\DropboxStreamer;
|
||||||
use App\Services\Streamers\LocalStreamerInterface;
|
use App\Services\Streamers\LocalStreamerInterface;
|
||||||
use App\Services\Streamers\S3CompatibleStreamer;
|
use App\Services\Streamers\S3CompatibleStreamer;
|
||||||
use App\Services\Streamers\StreamerInterface;
|
use App\Services\Streamers\StreamerInterface;
|
||||||
use App\Services\Streamers\TranscodingStreamer;
|
use App\Services\Streamers\TranscodingStreamer;
|
||||||
use App\Services\TranscodingService;
|
use App\Services\TranscodingService;
|
||||||
|
use App\Values\SongStorageMetadata\DropboxMetadata;
|
||||||
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
||||||
|
|
||||||
class StreamerFactory
|
class StreamerFactory
|
||||||
|
@ -23,27 +25,29 @@ class StreamerFactory
|
||||||
float $startTime = 0.0
|
float $startTime = 0.0
|
||||||
): StreamerInterface {
|
): StreamerInterface {
|
||||||
if ($song->storage_metadata instanceof S3CompatibleMetadata) {
|
if ($song->storage_metadata instanceof S3CompatibleMetadata) {
|
||||||
return tap(
|
return self::makeStreamerFromClass(S3CompatibleStreamer::class, $song);
|
||||||
app(S3CompatibleStreamer::class),
|
}
|
||||||
static fn (S3CompatibleStreamer $streamer) => $streamer->setSong($song)
|
|
||||||
);
|
if ($song->storage_metadata instanceof DropboxMetadata) {
|
||||||
|
return self::makeStreamerFromClass(DropboxStreamer::class, $song);
|
||||||
}
|
}
|
||||||
|
|
||||||
$transcode ??= $this->transcodingService->songShouldBeTranscoded($song);
|
$transcode ??= $this->transcodingService->songShouldBeTranscoded($song);
|
||||||
|
|
||||||
if ($transcode) {
|
if ($transcode) {
|
||||||
/** @var TranscodingStreamer $streamer */
|
/** @var TranscodingStreamer $streamer */
|
||||||
$streamer = app(TranscodingStreamer::class);
|
$streamer = self::makeStreamerFromClass(TranscodingStreamer::class, $song);
|
||||||
$streamer->setSong($song);
|
|
||||||
$streamer->setBitRate($bitRate ?: config('koel.streaming.bitrate'));
|
$streamer->setBitRate($bitRate ?: config('koel.streaming.bitrate'));
|
||||||
$streamer->setStartTime($startTime);
|
$streamer->setStartTime($startTime);
|
||||||
|
|
||||||
return $streamer;
|
return $streamer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tap(
|
return self::makeStreamerFromClass(LocalStreamerInterface::class, $song);
|
||||||
app(LocalStreamerInterface::class),
|
}
|
||||||
static fn (LocalStreamerInterface $streamer) => $streamer->setSong($song)
|
|
||||||
);
|
private static function makeStreamerFromClass(string $class, Song $song): StreamerInterface
|
||||||
|
{
|
||||||
|
return tap(app($class), static fn (StreamerInterface $streamer) => $streamer->setSong($song));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Builders\SongBuilder;
|
use App\Builders\SongBuilder;
|
||||||
|
use App\Values\SongStorageMetadata\DropboxMetadata;
|
||||||
use App\Values\SongStorageMetadata\LocalMetadata;
|
use App\Values\SongStorageMetadata\LocalMetadata;
|
||||||
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
use App\Values\SongStorageMetadata\S3CompatibleMetadata;
|
||||||
use App\Values\SongStorageMetadata\StorageMetadata;
|
use App\Values\SongStorageMetadata\SongStorageMetadata;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
@ -40,7 +41,7 @@ use Laravel\Scout\Searchable;
|
||||||
* @property int $owner_id
|
* @property int $owner_id
|
||||||
* @property bool $is_public
|
* @property bool $is_public
|
||||||
* @property User $owner
|
* @property User $owner
|
||||||
* @property-read StorageMetadata $storage_metadata
|
* @property-read SongStorageMetadata $storage_metadata
|
||||||
*
|
*
|
||||||
* // The following are only available for collaborative playlists
|
* // 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
|
* @property-read ?string $collaborator_email The email of the user who added the song to the playlist
|
||||||
|
@ -150,11 +151,15 @@ class Song extends Model
|
||||||
protected function storageMetadata(): Attribute
|
protected function storageMetadata(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
get: function (): StorageMetadata {
|
get: function (): SongStorageMetadata {
|
||||||
if (preg_match('/^s3:\\/\\/(.*)\\/(.*)/', $this->path, $matches)) {
|
if (preg_match('/^s3:\\/\\/(.*)\\/(.*)/', $this->path, $matches)) {
|
||||||
return S3CompatibleMetadata::make($matches[1], $matches[2]);
|
return S3CompatibleMetadata::make($matches[1], $matches[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^dropbox:\\/\\/(.*)\\/(.*)/', $this->path, $matches)) {
|
||||||
|
return DropboxMetadata::make($matches[1], $matches[2]);
|
||||||
|
}
|
||||||
|
|
||||||
return LocalMetadata::make($this->path);
|
return LocalMetadata::make($this->path);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\SongStorage\DropboxStorage;
|
||||||
use App\Services\SongStorage\LocalStorage;
|
use App\Services\SongStorage\LocalStorage;
|
||||||
use App\Services\SongStorage\S3CompatibleStorage;
|
use App\Services\SongStorage\S3CompatibleStorage;
|
||||||
use App\Services\SongStorage\SongStorage;
|
use App\Services\SongStorage\SongStorage;
|
||||||
|
@ -14,6 +15,7 @@ class SongStorageServiceProvider extends ServiceProvider
|
||||||
$this->app->bind(SongStorage::class, function () {
|
$this->app->bind(SongStorage::class, function () {
|
||||||
$concrete = match (config('koel.storage_driver')) {
|
$concrete = match (config('koel.storage_driver')) {
|
||||||
's3' => S3CompatibleStorage::class,
|
's3' => S3CompatibleStorage::class,
|
||||||
|
'dropbox' => DropboxStorage::class,
|
||||||
default => LocalStorage::class,
|
default => LocalStorage::class,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,5 +25,13 @@ class SongStorageServiceProvider extends ServiceProvider
|
||||||
$this->app->when(S3CompatibleStorage::class)
|
$this->app->when(S3CompatibleStorage::class)
|
||||||
->needs('$bucket')
|
->needs('$bucket')
|
||||||
->giveConfig('filesystems.disks.s3.bucket');
|
->giveConfig('filesystems.disks.s3.bucket');
|
||||||
|
|
||||||
|
$this->app->when(DropboxStorage::class)
|
||||||
|
->needs('$token')
|
||||||
|
->giveConfig('filesystems.disks.dropbox.token');
|
||||||
|
|
||||||
|
$this->app->when(DropboxStorage::class)
|
||||||
|
->needs('$folder')
|
||||||
|
->giveConfig('filesystems.disks.dropbox.folder');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
app/Services/SongStorage/CloudStorage.php
Normal file
44
app/Services/SongStorage/CloudStorage.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\SongStorage;
|
||||||
|
|
||||||
|
use App\Exceptions\SongUploadFailedException;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\FileScanner;
|
||||||
|
use App\Values\ScanConfiguration;
|
||||||
|
use App\Values\ScanResult;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Symfony\Component\Uid\Ulid;
|
||||||
|
|
||||||
|
abstract class CloudStorage implements SongStorage
|
||||||
|
{
|
||||||
|
public function __construct(protected FileScanner $scanner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function scanUploadedFile(UploadedFile $file, User $uploader): ScanResult
|
||||||
|
{
|
||||||
|
// Can't scan the uploaded file directly, as it apparently causes some misbehavior during idv3 tag reading.
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
$result = $this->scanner->setFile($tmpFile)
|
||||||
|
->scan(ScanConfiguration::make(
|
||||||
|
owner: $uploader,
|
||||||
|
makePublic: $uploader->preferences->makeUploadsPublic
|
||||||
|
));
|
||||||
|
|
||||||
|
throw_if($result->isError(), new SongUploadFailedException($result->error));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateStorageKey(string $filename, User $uploader): string
|
||||||
|
{
|
||||||
|
return sprintf('%s__%s__%s', $uploader->id, Str::lower(Ulid::generate()), $filename);
|
||||||
|
}
|
||||||
|
}
|
49
app/Services/SongStorage/DropboxStorage.php
Normal file
49
app/Services/SongStorage/DropboxStorage.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\SongStorage;
|
||||||
|
|
||||||
|
use App\Models\Song;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\FileScanner;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use League\Flysystem\Filesystem;
|
||||||
|
use Spatie\Dropbox\Client;
|
||||||
|
use Spatie\FlysystemDropbox\DropboxAdapter;
|
||||||
|
|
||||||
|
class DropboxStorage extends CloudStorage
|
||||||
|
{
|
||||||
|
private Filesystem $filesystem;
|
||||||
|
private DropboxAdapter $adapter;
|
||||||
|
|
||||||
|
public function __construct(protected FileScanner $scanner, private string $token, private string $folder)
|
||||||
|
{
|
||||||
|
parent::__construct($scanner);
|
||||||
|
|
||||||
|
$client = new Client($this->token);
|
||||||
|
$this->adapter = new DropboxAdapter($client);
|
||||||
|
$this->filesystem = new Filesystem($this->adapter, ['case_sensitive' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function storeUploadedFile(UploadedFile $file, User $uploader): Song
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($file, $uploader): Song {
|
||||||
|
$result = $this->scanUploadedFile($file, $uploader);
|
||||||
|
$song = $this->scanner->getSong();
|
||||||
|
$key = $this->generateStorageKey($file->getClientOriginalName(), $uploader);
|
||||||
|
|
||||||
|
$this->filesystem->write($key, File::get($result->path));
|
||||||
|
$song->update(['path' => "dropbox://$this->folder/$key"]);
|
||||||
|
|
||||||
|
File::delete($result->path);
|
||||||
|
|
||||||
|
return $song;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSongPresignedUrl(Song $song): string
|
||||||
|
{
|
||||||
|
return $this->adapter->getUrl($song->storage_metadata->getPath());
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,42 +5,29 @@ namespace App\Services\SongStorage;
|
||||||
use App\Models\Song;
|
use App\Models\Song;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\FileScanner;
|
use App\Services\FileScanner;
|
||||||
use App\Values\ScanConfiguration;
|
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Symfony\Component\Uid\Ulid;
|
|
||||||
|
|
||||||
class S3CompatibleStorage implements SongStorage
|
class S3CompatibleStorage extends CloudStorage
|
||||||
{
|
{
|
||||||
public function __construct(private FileScanner $scanner, private string $bucket)
|
public function __construct(protected FileScanner $scanner, private string $bucket)
|
||||||
{
|
{
|
||||||
|
parent::__construct($scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeUploadedFile(UploadedFile $file, User $uploader): Song
|
public function storeUploadedFile(UploadedFile $file, User $uploader): Song
|
||||||
{
|
{
|
||||||
// can't scan the uploaded file directly, as it may cause some misbehavior
|
return DB::transaction(function () use ($file, $uploader): Song {
|
||||||
// instead, we copy the file to the tmp directory and scan it from there
|
$result = $this->scanUploadedFile($file, $uploader);
|
||||||
$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();
|
$song = $this->scanner->getSong();
|
||||||
$key = $this->generateStorageKey($tmpFile->getFilename(), $uploader);
|
$key = $this->generateStorageKey($file->getClientOriginalName(), $uploader);
|
||||||
|
|
||||||
Storage::disk('s3')->put($key, $tmpFile->getContent());
|
Storage::disk('s3')->put($key, File::get($result->path));
|
||||||
$song->update(['path' => "s3://$this->bucket/$key"]);
|
$song->update(['path' => "s3://$this->bucket/$key"]);
|
||||||
|
|
||||||
File::delete($tmpFile->getRealPath());
|
File::delete($result->path);
|
||||||
|
|
||||||
return $song;
|
return $song;
|
||||||
});
|
});
|
||||||
|
@ -50,9 +37,4 @@ class S3CompatibleStorage implements SongStorage
|
||||||
{
|
{
|
||||||
return Storage::disk('s3')->temporaryUrl($song->storage_metadata->getPath(), now()->addHour());
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
20
app/Services/Streamers/DropboxStreamer.php
Normal file
20
app/Services/Streamers/DropboxStreamer.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Streamers;
|
||||||
|
|
||||||
|
use App\Services\SongStorage\DropboxStorage;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Routing\Redirector;
|
||||||
|
|
||||||
|
class DropboxStreamer extends Streamer
|
||||||
|
{
|
||||||
|
public function __construct(private DropboxStorage $storage)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream(): Redirector|RedirectResponse
|
||||||
|
{
|
||||||
|
return redirect($this->storage->getSongPresignedUrl($this->song));
|
||||||
|
}
|
||||||
|
}
|
20
app/Values/SongStorageMetadata/DropboxMetadata.php
Normal file
20
app/Values/SongStorageMetadata/DropboxMetadata.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Values\SongStorageMetadata;
|
||||||
|
|
||||||
|
class DropboxMetadata implements SongStorageMetadata
|
||||||
|
{
|
||||||
|
private function __construct(public string $appFolder, public string $key)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function make(string $appFolder, string $key): self
|
||||||
|
{
|
||||||
|
return new static($appFolder, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPath(): string
|
||||||
|
{
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Values\SongStorageMetadata;
|
namespace App\Values\SongStorageMetadata;
|
||||||
|
|
||||||
final class LocalMetadata implements StorageMetadata
|
final class LocalMetadata implements SongStorageMetadata
|
||||||
{
|
{
|
||||||
private function __construct(public string $path)
|
private function __construct(public string $path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Values\SongStorageMetadata;
|
|
||||||
|
|
||||||
final class R2Metadata extends S3CompatibleMetadata
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Values\SongStorageMetadata;
|
namespace App\Values\SongStorageMetadata;
|
||||||
|
|
||||||
class S3CompatibleMetadata implements StorageMetadata
|
class S3CompatibleMetadata implements SongStorageMetadata
|
||||||
{
|
{
|
||||||
private function __construct(public string $bucket, public string $key)
|
private function __construct(public string $bucket, public string $key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Values\SongStorageMetadata;
|
|
||||||
|
|
||||||
final class S3Metadata extends S3CompatibleMetadata
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Values\SongStorageMetadata;
|
namespace App\Values\SongStorageMetadata;
|
||||||
|
|
||||||
interface StorageMetadata
|
interface SongStorageMetadata
|
||||||
{
|
{
|
||||||
public function getPath(): string;
|
public function getPath(): string;
|
||||||
}
|
}
|
|
@ -36,7 +36,8 @@
|
||||||
"jwilsson/spotify-web-api-php": "^5.2",
|
"jwilsson/spotify-web-api-php": "^5.2",
|
||||||
"meilisearch/meilisearch-php": "^0.24.0",
|
"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"
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
|
"spatie/flysystem-dropbox": "^3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mockery/mockery": "~1.0",
|
"mockery/mockery": "~1.0",
|
||||||
|
|
209
composer.lock
generated
209
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6a64a8f7d4da75827254d63d4197bd51",
|
"content-hash": "7cf7d2bb1b51df5f49ca061698b6c4be",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "algolia/algoliasearch-client-php",
|
"name": "algolia/algoliasearch-client-php",
|
||||||
|
@ -1302,6 +1302,71 @@
|
||||||
],
|
],
|
||||||
"time": "2022-02-20T15:07:15+00:00"
|
"time": "2022-02-20T15:07:15+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "graham-campbell/guzzle-factory",
|
||||||
|
"version": "v7.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/GrahamCampbell/Guzzle-Factory.git",
|
||||||
|
"reference": "134f6ca38ad0c948ed7c22552a286bb56b5a5b35"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/GrahamCampbell/Guzzle-Factory/zipball/134f6ca38ad0c948ed7c22552a286bb56b5a5b35",
|
||||||
|
"reference": "134f6ca38ad0c948ed7c22552a286bb56b5a5b35",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/guzzle": "^7.8.1",
|
||||||
|
"guzzlehttp/psr7": "^2.6.2",
|
||||||
|
"php": "^7.4.15 || ^8.0.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"graham-campbell/analyzer": "^4.1",
|
||||||
|
"phpunit/phpunit": "^9.6.14 || ^10.5.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GrahamCampbell\\GuzzleFactory\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides A Simple Guzzle Factory With Good Defaults",
|
||||||
|
"keywords": [
|
||||||
|
"Graham Campbell",
|
||||||
|
"GrahamCampbell",
|
||||||
|
"Guzzle",
|
||||||
|
"Guzzle Factory",
|
||||||
|
"Guzzle-Factory",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/GrahamCampbell/Guzzle-Factory/issues",
|
||||||
|
"source": "https://github.com/GrahamCampbell/Guzzle-Factory/tree/v7.0.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/GrahamCampbell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/guzzle-factory",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-12-03T20:50:24+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "graham-campbell/result-type",
|
"name": "graham-campbell/result-type",
|
||||||
"version": "v1.1.0",
|
"version": "v1.1.0",
|
||||||
|
@ -5294,6 +5359,148 @@
|
||||||
],
|
],
|
||||||
"time": "2023-01-12T18:13:24+00:00"
|
"time": "2023-01-12T18:13:24+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spatie/dropbox-api",
|
||||||
|
"version": "1.22.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/spatie/dropbox-api.git",
|
||||||
|
"reference": "5b012d68568a560d1cd8888c0be2c2805c4b7c65"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/spatie/dropbox-api/zipball/5b012d68568a560d1cd8888c0be2c2805c4b7c65",
|
||||||
|
"reference": "5b012d68568a560d1cd8888c0be2c2805c4b7c65",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"graham-campbell/guzzle-factory": "^4.0.2|^5.0|^6.0|^7.0",
|
||||||
|
"guzzlehttp/guzzle": "^6.2|^7.0",
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"laravel/pint": "^1.10.1",
|
||||||
|
"phpstan/phpstan": "^1.10.16",
|
||||||
|
"phpunit/phpunit": "^9.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Spatie\\Dropbox\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alex Vanderbist",
|
||||||
|
"email": "alex.vanderbist@gmail.com",
|
||||||
|
"homepage": "https://spatie.be",
|
||||||
|
"role": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Freek Van der Herten",
|
||||||
|
"email": "freek@spatie.be",
|
||||||
|
"homepage": "https://spatie.be",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A minimal implementation of Dropbox API v2",
|
||||||
|
"homepage": "https://github.com/spatie/dropbox-api",
|
||||||
|
"keywords": [
|
||||||
|
"Dropbox-API",
|
||||||
|
"api",
|
||||||
|
"dropbox",
|
||||||
|
"spatie",
|
||||||
|
"v2"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/spatie/dropbox-api/issues",
|
||||||
|
"source": "https://github.com/spatie/dropbox-api/tree/1.22.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://spatie.be/open-source/support-us",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/spatie",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-06-08T07:13:00+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spatie/flysystem-dropbox",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/spatie/flysystem-dropbox.git",
|
||||||
|
"reference": "766879111204a6e49412b5ff5989a6654e1b8ae0"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/spatie/flysystem-dropbox/zipball/766879111204a6e49412b5ff5989a6654e1b8ae0",
|
||||||
|
"reference": "766879111204a6e49412b5ff5989a6654e1b8ae0",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"league/flysystem": "^3.7.0",
|
||||||
|
"php": "^8.0",
|
||||||
|
"spatie/dropbox-api": "^1.17.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"pestphp/pest": "^1.22",
|
||||||
|
"phpspec/prophecy-phpunit": "^2.0.1",
|
||||||
|
"phpunit/phpunit": "^9.5.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Spatie\\FlysystemDropbox\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alex Vanderbist",
|
||||||
|
"email": "alex.vanderbist@gmail.com",
|
||||||
|
"homepage": "https://spatie.be",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Flysystem Adapter for the Dropbox v2 API",
|
||||||
|
"homepage": "https://github.com/spatie/flysystem-dropbox",
|
||||||
|
"keywords": [
|
||||||
|
"Flysystem",
|
||||||
|
"api",
|
||||||
|
"dropbox",
|
||||||
|
"flysystem-dropbox",
|
||||||
|
"spatie",
|
||||||
|
"v2"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/spatie/flysystem-dropbox/issues",
|
||||||
|
"source": "https://github.com/spatie/flysystem-dropbox/tree/3.0.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://spatie.be/open-source/support-us",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/spatie",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-07-17T07:48:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v6.0.19",
|
"version": "v6.0.19",
|
||||||
|
|
|
@ -72,6 +72,11 @@ return [
|
||||||
'throw' => true,
|
'throw' => true,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'dropbox' => [
|
||||||
|
'token' => env('DROPBOX_ACCESS_TOKEN'),
|
||||||
|
'folder' => env('DROPBOX_APP_FOLDER'),
|
||||||
|
],
|
||||||
|
|
||||||
'rackspace' => [
|
'rackspace' => [
|
||||||
'driver' => 'rackspace',
|
'driver' => 'rackspace',
|
||||||
'username' => 'your-username',
|
'username' => 'your-username',
|
||||||
|
|
Loading…
Reference in a new issue