feat(admin): rebuild release upload form with Livewire and CDN validation
Replace the server-rendered release upload form with a Livewire component, introducing an interactive admin release form that supports dynamic episode management, real‑time CDN path validation, and direct download file checks. Key changes: - New `AdminReleaseForm` Livewire component with dynamic episode fields, Tagify integration, and upload handling via Livewire's file uploads. - Added `CdnPathValidator` service to verify download and stream paths across all configured mirrors, caching results and capturing file sizes. - Extended `EpisodeService` and `GalleryService` to support array‑based data and temporary uploaded files from Livewire. - Persist validated download sizes and store the validation timestamp on the `downloads` table via a new migration; also add a unique constraint on `hentais.slug` to prevent duplicates. - Remove the old POST `/admin/release/upload` route and controller logic, along with the legacy `upload.js` script. - Add comprehensive feature and unit tests covering the new component and the CDN validation service.
This commit is contained in:
@@ -6,9 +6,11 @@ use App\Models\Episode;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Hentai;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Intervention\Image\Encoders\WebpEncoder;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||
|
||||
class GalleryService
|
||||
{
|
||||
@@ -17,17 +19,26 @@ class GalleryService
|
||||
$galleryInputNumber = $override ? 1 : $episodeNumber;
|
||||
|
||||
if ($request->hasFile('episodegallery'.$galleryInputNumber)) {
|
||||
$this->saveGalleryFiles($hentai, $episode, $episodeNumber, $request->file('episodegallery'.$galleryInputNumber));
|
||||
}
|
||||
}
|
||||
|
||||
$this->deleteOldGallery($episode);
|
||||
/**
|
||||
* Save a gallery for the given episode from a list of uploaded files.
|
||||
*
|
||||
* @param array<int, UploadedFile|TemporaryUploadedFile> $files
|
||||
*/
|
||||
public function saveGalleryFiles(Hentai $hentai, Episode $episode, int $episodeNumber, array $files): void
|
||||
{
|
||||
$this->deleteOldGallery($episode);
|
||||
|
||||
$this->createGalleryFolder($hentai);
|
||||
$this->createGalleryFolder($hentai);
|
||||
|
||||
$counter = 0;
|
||||
foreach ($request->file('episodegallery'.$galleryInputNumber) as $file) {
|
||||
$gallery = $this->createGallery($hentai, $episode, $episodeNumber, $counter);
|
||||
$this->saveGalleryImage($gallery, $file);
|
||||
$counter += 1;
|
||||
}
|
||||
$counter = 0;
|
||||
foreach ($files as $file) {
|
||||
$gallery = $this->createGallery($hentai, $episode, $episodeNumber, $counter);
|
||||
$this->saveGalleryImage($gallery, $file);
|
||||
$counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +62,7 @@ class GalleryService
|
||||
return $gallery;
|
||||
}
|
||||
|
||||
private function saveGalleryImage(Gallery $gallery, $sourceImage): void
|
||||
private function saveGalleryImage(Gallery $gallery, UploadedFile|TemporaryUploadedFile $sourceImage): void
|
||||
{
|
||||
Image::read($sourceImage->getRealPath())
|
||||
->cover(1920, 1080)
|
||||
|
||||
Reference in New Issue
Block a user