- Mediathek: Video-Vorschaubilder statt Icons (FFmpeg-Thumbnails + Backfill-Command), Kategorie "Sonstiges" - B2in Media-Picker zeigt alle Medientypen, Typ wird automatisch erkannt; Thumbnail-Preview vor allen Medien-URL-Feldern - B2in Marke/Footer: Footer ein/aus, Logo+Claim frei positionierbar (Ecken) mit Constraints, separate Anzeige-Schalter - Angebote-Modul dynamisch: kein Slide-Typ mehr, einheitliches Detail-Layout mit ein-/ausblendbaren Bloecken, Logo/Brand pro Slide, Streichpreis-Option - Player: leere Module stoppen Endlosschleife, dynamische Layout-Anpassung bei verstecktem Footer/Header - Fix: Script-Ladereihenfolge (Livewire vor Flux), entfernte stale public/flux/flux.js, Modal-Crash beim Aktualisieren behoben Co-authored-by: Cursor <cursoragent@cursor.com>
59 lines
1.7 KiB
PHP
59 lines
1.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\DisplayMedia;
|
|
use App\Services\DisplayMediaService;
|
|
use Illuminate\Console\Command;
|
|
|
|
class GenerateVideoThumbnails extends Command
|
|
{
|
|
protected $signature = 'display-media:generate-video-thumbnails
|
|
{--force : Regenerate posters even if a thumbnail already exists}';
|
|
|
|
protected $description = 'Generate poster frames for uploaded display media videos using ffmpeg';
|
|
|
|
public function handle(DisplayMediaService $service): int
|
|
{
|
|
$query = DisplayMedia::query()
|
|
->where('type', 'video')
|
|
->where('source_type', 'upload');
|
|
|
|
if (! $this->option('force')) {
|
|
$query->whereNull('thumbnail_path');
|
|
}
|
|
|
|
$videos = $query->get();
|
|
|
|
if ($videos->isEmpty()) {
|
|
$this->info('Keine Videos zum Verarbeiten gefunden.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info(sprintf('%d Video(s) werden verarbeitet...', $videos->count()));
|
|
|
|
$generated = 0;
|
|
$failed = 0;
|
|
|
|
foreach ($videos as $video) {
|
|
$thumbnailPath = $service->generateVideoThumbnail($video);
|
|
|
|
if ($thumbnailPath !== null) {
|
|
$video->update(['thumbnail_path' => $thumbnailPath]);
|
|
$this->line(" <info>✓</info> {$video->getDisplayName()}");
|
|
$generated++;
|
|
} else {
|
|
$this->warn(" ✗ {$video->getDisplayName()} (Poster konnte nicht erzeugt werden)");
|
|
$failed++;
|
|
}
|
|
}
|
|
|
|
$this->newLine();
|
|
$this->info(sprintf('Fertig: %d erzeugt, %d fehlgeschlagen.', $generated, $failed));
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|