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:
2026-08-08 13:18:57 +02:00
parent 2076517ebd
commit 30a6b080eb
19 changed files with 1503 additions and 310 deletions
+24
View File
@@ -33,4 +33,28 @@ class DownloadService
}
}
}
/**
* Persist validated download URLs for an episode. Sizes are written
* directly from the CDN validation response, so no size job is dispatched.
*
* @param array<string, array{url: string, size?: float|int|null}> $downloads
*/
public function createOrUpdateDownloadsFromArray(Episode $episode, array $downloads): void
{
foreach ($downloads as $type => $data) {
if (empty($data['url'])) {
continue;
}
Downloads::updateOrCreate([
'episode_id' => $episode->id,
'type' => $type,
], [
'url' => $data['url'],
'size' => $data['size'] ?? null,
'validated_at' => now(),
]);
}
}
}