koel/app/Services/SongStorage/DropboxStorage.php
2024-07-06 17:44:46 +02:00

101 lines
3 KiB
PHP

<?php
namespace App\Services\SongStorage;
use App\Models\Song;
use App\Models\User;
use App\Services\FileScanner;
use App\Values\SongStorageTypes;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client;
use Spatie\FlysystemDropbox\DropboxAdapter;
final class DropboxStorage extends CloudStorage
{
public Filesystem $filesystem;
private DropboxAdapter $adapter;
public function __construct(protected FileScanner $scanner, private array $config)
{
parent::__construct($scanner);
$client = new Client($this->maybeRefreshAccessToken());
$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://$key",
'storage' => SongStorageTypes::DROPBOX,
]);
File::delete($result->path);
return $song;
});
}
private function maybeRefreshAccessToken(): string
{
$accessToken = Cache::get('dropbox_access_token');
if ($accessToken) {
return $accessToken;
}
$response = Http::asForm()
->withBasicAuth($this->config['app_key'], $this->config['app_secret'])
->post('https://api.dropboxapi.com/oauth2/token', [
'refresh_token' => $this->config['refresh_token'],
'grant_type' => 'refresh_token',
])->json();
Cache::put(
'dropbox_access_token',
$response['access_token'],
now()->addSeconds($response['expires_in'] - 60) // 60 seconds buffer
);
return $response['access_token'];
}
public function getSongPresignedUrl(Song $song): string
{
return $this->adapter->getUrl($song->storage_metadata->getPath());
}
public function supported(): bool
{
return SongStorageTypes::supported(SongStorageTypes::DROPBOX);
}
public function delete(Song $song, bool $backup = false): void
{
$path = $song->storage_metadata->getPath();
if ($backup) {
$this->filesystem->move($path, "backup/$path");
}
$this->filesystem->delete($path);
}
public function testSetup(): void
{
$this->filesystem->write('test.txt', 'Koel test file.');
$this->filesystem->delete('test.txt');
}
}