pp-planer/app/Support/CcliLabels.php

73 lines
2.4 KiB
PHP

<?php
namespace App\Support;
final class CcliLabels
{
/**
* Regex matching CCLI SongSelect section labels (English + German + variants).
*/
public const SECTION_LABEL_PATTERN = '/^(Verse|Chorus|Bridge|Pre-Chorus|Tag|Ending|Intro|Interlude|Outro|Misc|Strophe|Refrain|Brücke|Vorrefrain|Schluss|Zwischenspiel)\s*(\d+[a-z]?)?\s*(?:\((?:Repeat|Wdh\.?)\))?\s*(?:[xX]\s*\d+)?$/iu';
/**
* Regex matching CCLI footer/metadata lines (copyright, CCLI number).
*/
public const METADATA_PATTERN = '/©|CCLI[\s\-]|ccli\.com|SongSelect|All rights reserved|Alle Rechte vorbehalten/iu';
/**
* Bidirectional English ↔ German label kind mapping.
*/
public const LABEL_NAME_MAP = [
'Strophe' => 'Verse',
'Refrain' => 'Chorus',
'Brücke' => 'Bridge',
'Vorrefrain' => 'Pre-Chorus',
'Schluss' => 'Ending',
'Zwischenspiel' => 'Interlude',
];
public static function isSectionLabel(string $line): bool
{
return (bool) preg_match(self::SECTION_LABEL_PATTERN, trim($line));
}
public static function isMetadataLine(string $line): bool
{
return (bool) preg_match(self::METADATA_PATTERN, $line);
}
public static function normalizeLabelName(string $label): string
{
$trimmed = trim($label);
if (! preg_match('/^(?<kind>Verse|Chorus|Bridge|Pre-Chorus|Tag|Ending|Intro|Interlude|Outro|Misc|Strophe|Refrain|Brücke|Vorrefrain|Schluss|Zwischenspiel)(?<suffix>\s+\d+[a-z]?)?$/iu', $trimmed, $matches)) {
return $trimmed;
}
$kind = $matches['kind'];
$suffix = $matches['suffix'] ?? '';
return (self::LABEL_NAME_MAP[$kind] ?? $kind).$suffix;
}
/**
* @return array{kind: string, number: string|null, modifier: string|null}|null
*/
public static function parseLabel(string $line): ?array
{
$trimmed = trim($line);
if (! preg_match('/^(?<kind>Verse|Chorus|Bridge|Pre-Chorus|Tag|Ending|Intro|Interlude|Outro|Misc|Strophe|Refrain|Brücke|Vorrefrain|Schluss|Zwischenspiel)(?:\s+(?<number>\d+[a-z]?))?(?:\s*\((?<modifier>Repeat|Wdh\.?)\))?(?:\s*[xX]\s*\d+)?$/iu', $trimmed, $matches)) {
return null;
}
$modifier = $matches['modifier'] ?? null;
return [
'kind' => $matches['kind'],
'number' => $matches['number'] ?? null,
'modifier' => $modifier !== null ? rtrim($modifier, '.') : null,
];
}
}