From be6d12fcb679bb77edbdc46bb3f7d8c03642cf42 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 24 Jan 2021 13:30:31 -0700 Subject: [PATCH] Update MediaPipeline, handle cloud object storage --- .../ImageOptimizePipeline/ImageUpdate.php | 5 +- .../MediaPipeline/MediaStoragePipeline.php | 31 ++++++++++ app/Media.php | 8 +-- app/Services/MediaStorageService.php | 62 ++++++++++++++++++- 4 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 app/Jobs/MediaPipeline/MediaStoragePipeline.php diff --git a/app/Jobs/ImageOptimizePipeline/ImageUpdate.php b/app/Jobs/ImageOptimizePipeline/ImageUpdate.php index 747820b38..367396df8 100644 --- a/app/Jobs/ImageOptimizePipeline/ImageUpdate.php +++ b/app/Jobs/ImageOptimizePipeline/ImageUpdate.php @@ -12,7 +12,7 @@ use Illuminate\Queue\SerializesModels; use ImageOptimizer; use Illuminate\Http\File; use App\Services\MediaPathService; -use App\Services\MediaStorageService; +use App\Jobs\MediaPipeline\MediaStoragePipeline; class ImageUpdate implements ShouldQueue { @@ -77,6 +77,7 @@ class ImageUpdate implements ShouldQueue $media->size = $total; $media->save(); - MediaStorageService::store($media); + MediaStoragePipeline::dispatch($media); + } } diff --git a/app/Jobs/MediaPipeline/MediaStoragePipeline.php b/app/Jobs/MediaPipeline/MediaStoragePipeline.php new file mode 100644 index 000000000..61f80767c --- /dev/null +++ b/app/Jobs/MediaPipeline/MediaStoragePipeline.php @@ -0,0 +1,31 @@ +media = $media; + } + + public function handle() + { + MediaStorageService::store($this->media); + } + +} \ No newline at end of file diff --git a/app/Media.php b/app/Media.php index 9ea9c79a7..3854c3848 100644 --- a/app/Media.php +++ b/app/Media.php @@ -33,7 +33,7 @@ class Media extends Model return $this->cdn_url; } - if(!empty($this->remote_media) && $this->remote_url) { + if($this->remote_media && $this->remote_url) { return $this->remote_url; } @@ -46,10 +46,8 @@ class Media extends Model return $this->thumbnail_url; } - if($this->remote_url || $this->thumbnail_path) { - return url(Storage::url( - $this->remote_url ?? - $this->thumbnail_path)); + if(!$this->remote_media && $this->thumbnail_path) { + return url(Storage::url($this->thumbnail_path)); } return url(Storage::url('public/no-preview.png')); diff --git a/app/Services/MediaStorageService.php b/app/Services/MediaStorageService.php index a6a1d843f..db7faf52c 100644 --- a/app/Services/MediaStorageService.php +++ b/app/Services/MediaStorageService.php @@ -11,6 +11,7 @@ use Illuminate\Support\Str; use App\Media; use App\Profile; use App\User; +use GuzzleHttp\Client; class MediaStorageService { @@ -23,6 +24,17 @@ class MediaStorageService { return; } + public static function head($url) + { + $c = new Client(); + $r = $c->request('HEAD', $url); + $h = $r->getHeaders(); + return [ + 'length' => $h['Content-Length'][0], + 'mime' => $h['Content-Type'][0] + ]; + } + protected function cloudStore($media) { if($media->remote_media == true) { @@ -51,6 +63,7 @@ class MediaStorageService { $media->thumbnail_url = $thumbUrl; $media->cdn_url = $url; $media->optimized_url = $url; + $media->replicated_at = now(); $media->save(); if($media->status_id) { Cache::forget('status:transformer:media:attachments:' . $media->status_id); @@ -59,6 +72,53 @@ class MediaStorageService { protected function remoteToCloud($media) { - // todo + $url = $media->remote_url; + + if(!Helpers::validateUrl($url)) { + return; + } + + $head = $this->head($media->remote_url); + $mimes = [ + 'image/jpeg', + 'image/png', + 'video/mp4' + ]; + + $mime = $head['mime']; + $max_size = (int) config('pixelfed.max_photo_size') * 1000; + $media->size = $head['length']; + $media->remote_media = true; + $media->save(); + + if(!in_array($mime, $mimes)) { + return; + } + + if($head['length'] == $max_size) { + return; + } + + $ext = $mime == 'image/jpeg' ? '.jpg' : ($mime == 'image/png' ? '.png' : 'mp4'); + + $base = MediaPathService::get($media->profile); + $path = Str::random(40) . $ext; + $tmpBase = storage_path('app/remcache/'); + $tmpPath = $media->profile_id . '-' . $path; + $tmpName = $tmpBase . $tmpPath; + $data = file_get_contents($url, false, null, 0, $head['length']); + file_put_contents($tmpName, $data); + $hash = hash_file('sha256', $tmpName); + + $disk = Storage::disk(config('filesystems.cloud')); + $file = $disk->putFileAs($base, new File($tmpName), $path, 'public'); + $permalink = $disk->url($file); + $media->cdn_url = $permalink; + $media->original_sha256 = $hash; + $media->replicated_at = now(); + $media->save(); + + unlink($tmpName); + } } \ No newline at end of file