- populate COPYRIGHT (title/author/copyright/CCLI) + blank slides on every song; songHasContent ignores locked sections - foreground info/moderation images now bundle-relative (fixes blank images) - pre-added .probundle injection: Zip64-fix + verbatim .pro extraction (fixes empty bundle) - nametag subtitle split (text + subtitle); smaller non-bold render - skip songs with no content slides at export with German warning - link service agenda songs to SongDB edit modal via #song-<id> - allow CCLI import of metadata-only songs (no lyric sections) - expose has_content_slides on service songs; show "Keine Inhaltsfolien"
171 lines
5 KiB
PHP
171 lines
5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Label;
|
|
use App\Models\Setting;
|
|
use App\Models\Song;
|
|
use App\Models\SongArrangement;
|
|
use App\Models\SongArrangementSection;
|
|
use App\Models\SongSection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class SongPrefixPostfixService
|
|
{
|
|
public function ensure(Song $song): void
|
|
{
|
|
DB::transaction(function () use ($song): void {
|
|
$prefixLabelId = $this->resolvePrefixLabelId();
|
|
$postfixLabelId = $this->resolvePostfixLabelId();
|
|
|
|
$prefixSection = $this->ensureLockedSection($song, $prefixLabelId, 0, 'prefix');
|
|
$postfixSection = $this->ensureLockedSection($song, $postfixLabelId, PHP_INT_MAX, 'postfix');
|
|
|
|
$arrangement = $this->resolveDefaultArrangement($song);
|
|
|
|
$this->ensureSectionInArrangement($arrangement, $prefixSection, 'first');
|
|
$this->ensureSectionInArrangement($arrangement, $postfixSection, 'last');
|
|
});
|
|
}
|
|
|
|
private function resolvePrefixLabelId(): int
|
|
{
|
|
$id = Setting::get('song_prefix_label_id');
|
|
|
|
if ($id !== null && $id !== '') {
|
|
return (int) $id;
|
|
}
|
|
|
|
$label = Label::firstOrCreate(
|
|
['name' => 'COPYRIGHT'],
|
|
['color' => '#24B34C'],
|
|
);
|
|
|
|
Setting::set('song_prefix_label_id', (string) $label->id);
|
|
|
|
return $label->id;
|
|
}
|
|
|
|
private function resolvePostfixLabelId(): int
|
|
{
|
|
$id = Setting::get('song_postfix_label_id');
|
|
|
|
if ($id !== null && $id !== '') {
|
|
return (int) $id;
|
|
}
|
|
|
|
$label = Label::firstOrCreate(
|
|
['name' => 'BLANK'],
|
|
['color' => '#000000'],
|
|
);
|
|
|
|
Setting::set('song_postfix_label_id', (string) $label->id);
|
|
|
|
return $label->id;
|
|
}
|
|
|
|
/**
|
|
* @param 'prefix'|'postfix' $kind
|
|
*/
|
|
private function ensureLockedSection(Song $song, int $labelId, int $orderHint, string $kind): SongSection
|
|
{
|
|
$section = SongSection::firstOrCreate(
|
|
['song_id' => $song->id, 'label_id' => $labelId],
|
|
['order' => $orderHint, 'locked' => true],
|
|
);
|
|
|
|
$section->update(['locked' => true]);
|
|
$section->slides()->delete();
|
|
|
|
$textContent = $kind === 'prefix'
|
|
? $this->buildCopyrightText($song)
|
|
: '';
|
|
|
|
$section->slides()->create([
|
|
'order' => 1,
|
|
'text_content' => $textContent,
|
|
]);
|
|
|
|
return $section;
|
|
}
|
|
|
|
private function buildCopyrightText(Song $song): string
|
|
{
|
|
$title = trim((string) ($song->title ?? $song->name ?? ''));
|
|
|
|
$lines = [];
|
|
|
|
if ($title !== '') {
|
|
$lines[] = $title;
|
|
}
|
|
|
|
if (trim((string) $song->author) !== '') {
|
|
$lines[] = trim((string) $song->author);
|
|
}
|
|
|
|
if (trim((string) $song->copyright_text) !== '') {
|
|
$lines[] = trim((string) $song->copyright_text);
|
|
}
|
|
|
|
if (trim((string) $song->ccli_id) !== '') {
|
|
$lines[] = 'CCLI-Liednr. '.trim((string) $song->ccli_id);
|
|
}
|
|
|
|
return implode("\n", $lines);
|
|
}
|
|
|
|
private function resolveDefaultArrangement(Song $song): SongArrangement
|
|
{
|
|
return SongArrangement::firstOrCreate(
|
|
['song_id' => $song->id, 'name' => 'normal'],
|
|
['is_default' => true],
|
|
);
|
|
}
|
|
|
|
private function ensureSectionInArrangement(
|
|
SongArrangement $arrangement,
|
|
SongSection $section,
|
|
string $position,
|
|
): void {
|
|
$existing = SongArrangementSection::where('song_arrangement_id', $arrangement->id)
|
|
->where('song_section_id', $section->id)
|
|
->first();
|
|
|
|
if ($position === 'first') {
|
|
if ($existing === null) {
|
|
SongArrangementSection::where('song_arrangement_id', $arrangement->id)
|
|
->increment('order');
|
|
|
|
SongArrangementSection::create([
|
|
'song_arrangement_id' => $arrangement->id,
|
|
'song_section_id' => $section->id,
|
|
'order' => 0,
|
|
]);
|
|
} else {
|
|
if ($existing->order !== 0) {
|
|
SongArrangementSection::where('song_arrangement_id', $arrangement->id)
|
|
->where('id', '!=', $existing->id)
|
|
->where('order', '<', $existing->order)
|
|
->increment('order');
|
|
|
|
$existing->update(['order' => 0]);
|
|
}
|
|
}
|
|
} else {
|
|
$maxOrder = SongArrangementSection::where('song_arrangement_id', $arrangement->id)
|
|
->where('song_section_id', '!=', $section->id)
|
|
->max('order') ?? 0;
|
|
|
|
if ($existing === null) {
|
|
SongArrangementSection::create([
|
|
'song_arrangement_id' => $arrangement->id,
|
|
'song_section_id' => $section->id,
|
|
'order' => $maxOrder + 1,
|
|
]);
|
|
} else {
|
|
$existing->update(['order' => $maxOrder + 1]);
|
|
}
|
|
}
|
|
}
|
|
}
|