Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
152 lines
4.9 KiB
PHP
152 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Service;
|
|
use App\Models\ServiceAgendaItem;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use InvalidArgumentException;
|
|
use ProPresenter\Parser\PresentationBundle;
|
|
use ProPresenter\Parser\ProBundleWriter;
|
|
use ProPresenter\Parser\ProFileGenerator;
|
|
use RuntimeException;
|
|
|
|
class ProBundleExportService
|
|
{
|
|
private const ALLOWED_BLOCK_TYPES = ['information', 'moderation', 'sermon'];
|
|
|
|
public function __construct(
|
|
private readonly MacroResolutionService $macroResolutionService,
|
|
) {}
|
|
|
|
public function generateBundle(Service $service, string $blockType): string
|
|
{
|
|
if (! in_array($blockType, self::ALLOWED_BLOCK_TYPES, true)) {
|
|
throw new InvalidArgumentException('Ungültiger Blocktyp für .probundle Export.');
|
|
}
|
|
|
|
$slides = $service->slides()
|
|
->where('type', $blockType)
|
|
->orderBy('sort_order')
|
|
->get();
|
|
|
|
$groupName = ucfirst($blockType);
|
|
|
|
return $this->buildBundleFromSlides($slides, $groupName, $service, $blockType);
|
|
}
|
|
|
|
public function generateAgendaItemBundle(ServiceAgendaItem $agendaItem): string
|
|
{
|
|
$agendaItem->loadMissing([
|
|
'service',
|
|
'slides',
|
|
'serviceSong.song.arrangements.arrangementLabels.label.songSlides',
|
|
]);
|
|
|
|
$title = $agendaItem->title ?: 'Ablauf-Element';
|
|
|
|
if ($agendaItem->serviceSong?->song_id && $agendaItem->serviceSong->song) {
|
|
$song = $agendaItem->serviceSong->song;
|
|
|
|
$labelCount = $song->arrangements()
|
|
->withCount('arrangementLabels')
|
|
->get()
|
|
->sum('arrangement_labels_count');
|
|
|
|
if ($labelCount === 0) {
|
|
throw new RuntimeException('Song "'.$song->title.'" hat keine Gruppen.');
|
|
}
|
|
|
|
$parserSong = app(ProExportService::class)->generateParserSong($song, $agendaItem->service);
|
|
$proFilename = self::safeFilename($song->title).'.pro';
|
|
|
|
$bundle = new PresentationBundle($parserSong, $proFilename);
|
|
$bundlePath = sys_get_temp_dir().'/'.uniqid('agenda-song-').'.probundle';
|
|
ProBundleWriter::write($bundle, $bundlePath);
|
|
|
|
return $bundlePath;
|
|
}
|
|
|
|
$slides = $agendaItem->slides()
|
|
->whereNull('deleted_at')
|
|
->orderBy('sort_order')
|
|
->get();
|
|
|
|
return $this->buildBundleFromSlides($slides, $title, $agendaItem->service, 'agenda_item');
|
|
}
|
|
|
|
/** @param \Illuminate\Database\Eloquent\Collection<int, \App\Models\Slide> $slides */
|
|
private function buildBundleFromSlides($slides, string $groupName, ?Service $service = null, ?string $partType = null): string
|
|
{
|
|
$slideData = [];
|
|
$mediaFiles = [];
|
|
|
|
foreach ($slides as $slide) {
|
|
$sourcePath = Storage::disk('public')->path($slide->stored_filename);
|
|
if (! file_exists($sourcePath)) {
|
|
continue;
|
|
}
|
|
|
|
$imageFilename = basename($slide->stored_filename);
|
|
$imageContent = file_get_contents($sourcePath);
|
|
if ($imageContent === false) {
|
|
continue;
|
|
}
|
|
|
|
$mediaFiles[$imageFilename] = $imageContent;
|
|
|
|
$singleSlideData = [
|
|
'media' => $imageFilename,
|
|
'format' => 'JPG',
|
|
'label' => $slide->original_filename,
|
|
];
|
|
|
|
if ($service !== null && $partType !== null) {
|
|
$slideIndex = count($slideData);
|
|
$totalSlides = $slides->count();
|
|
$macros = $this->macroResolutionService->macrosForSlide(
|
|
$service,
|
|
$partType,
|
|
['index' => $slideIndex, 'total' => $totalSlides, 'label_id' => null],
|
|
);
|
|
|
|
if (! empty($macros)) {
|
|
// ProPresenter parser currently supports one `macro` entry per slide
|
|
$singleSlideData['macro'] = $macros[0];
|
|
}
|
|
}
|
|
|
|
$slideData[] = $singleSlideData;
|
|
}
|
|
|
|
$groups = [
|
|
[
|
|
'name' => $groupName,
|
|
'color' => [0, 0, 0, 1],
|
|
'slides' => $slideData,
|
|
],
|
|
];
|
|
|
|
$arrangements = [
|
|
[
|
|
'name' => 'normal',
|
|
'groupNames' => [$groupName],
|
|
],
|
|
];
|
|
|
|
$song = ProFileGenerator::generate($groupName, $groups, $arrangements);
|
|
$proFilename = self::safeFilename($groupName).'.pro';
|
|
|
|
$bundle = new PresentationBundle($song, $proFilename, $mediaFiles);
|
|
$bundlePath = sys_get_temp_dir().'/'.uniqid('bundle-').'.probundle';
|
|
ProBundleWriter::write($bundle, $bundlePath);
|
|
|
|
return $bundlePath;
|
|
}
|
|
|
|
private static function safeFilename(string $name): string
|
|
{
|
|
return preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $name) ?: 'presentation';
|
|
}
|
|
}
|