refactor(episode): migrate episode upload to Livewire with real-time CDN verification

Replace the server-rendered episode upload form with a Livewire component,
introducing an interactive admin experience that validates the new episode's
stream path against all configured mirrors before saving. The controller-based
`store` method and its route are removed, and episode creation now flows
through the `AdminEpisodeForm` component with frontend upload handling and
dynamic quality checks.

Key changes:
- Add `AdminEpisodeForm` Livewire component with file uploads, tag handling,
  and debounced stream/base-url validation.
- Extend `CdnPathValidator::validateStream` to accept an episode number so the
  manifest path can point to the specific episode being added.
- Remove the `store` method from `EpisodeController` and its POST route.
- Delete the legacy `createEpisode` method from `EpisodeService`.
- Replace the Blade upload modal with the Livewire view, including progress
  indicators and validation badges.
- Add feature tests for the Livewire component and update unit tests for the
  CDN validator's episode-specific manifest check.
This commit is contained in:
2026-08-08 14:29:05 +02:00
parent 30a6b080eb
commit d08e280ce0
9 changed files with 774 additions and 136 deletions
@@ -30,34 +30,6 @@ class EpisodeController extends Controller
$this->downloadService = $downloadService;
}
/**
* Add Episode to existing series
*/
public function store(Request $request): RedirectResponse
{
$referenceEpisode = Episode::with('hentai')->where('id', $request->input('episode_id'))->firstOrFail();
$episodeNumber = $referenceEpisode->hentai->episodes()->count() + 1;
// Create Episode
$episode = $this->episodeService->createEpisode($request, $referenceEpisode->hentai, $episodeNumber, null, $referenceEpisode);
$this->episodeService->createOrUpdateCover($request, $episode, $referenceEpisode->hentai->slug, 1);
$this->downloadService->createOrUpdateDownloads($request, $episode, 1);
$this->galleryService->createOrUpdateGallery($request, $referenceEpisode->hentai, $episode, $episodeNumber, true);
// Discord Alert
if ($request->has('censored')) {
DiscordReleaseNotification::dispatch($referenceEpisode->title.' - '.$episodeNumber, 'release-censored');
} else {
DiscordReleaseNotification::dispatch($episode->slug, 'release');
}
cache()->flush();
return to_route('hentai.index', [
'title' => $episode->slug,
]);
}
/**
* Edit Episode
*/