[AI] add slide label, macro, and media support
This commit is contained in:
parent
addda54957
commit
3a33597bcf
|
|
@ -4,7 +4,12 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace ProPresenter\Parser;
|
namespace ProPresenter\Parser;
|
||||||
|
|
||||||
|
use Rv\Data\Action;
|
||||||
|
use Rv\Data\Action\ActionType;
|
||||||
|
use Rv\Data\Action\MacroType;
|
||||||
|
use Rv\Data\CollectionElementType;
|
||||||
use Rv\Data\Cue;
|
use Rv\Data\Cue;
|
||||||
|
use Rv\Data\UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read wrapper around a protobuf Cue representing a slide.
|
* Read wrapper around a protobuf Cue representing a slide.
|
||||||
|
|
@ -126,6 +131,122 @@ class Slide
|
||||||
$textElements[1]->setPlainText($text);
|
$textElements[1]->setPlainText($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLabel(): string
|
||||||
|
{
|
||||||
|
return $this->cue->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLabel(string $label): void
|
||||||
|
{
|
||||||
|
$this->cue->setName($label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasMacro(): bool
|
||||||
|
{
|
||||||
|
return $this->findMacroAction() !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMacroName(): ?string
|
||||||
|
{
|
||||||
|
$macro = $this->findMacroAction();
|
||||||
|
return $macro?->getMacro()?->getIdentification()?->getParameterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMacroUuid(): ?string
|
||||||
|
{
|
||||||
|
$macro = $this->findMacroAction();
|
||||||
|
return $macro?->getMacro()?->getIdentification()?->getParameterUuid()?->getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMacroCollectionName(): ?string
|
||||||
|
{
|
||||||
|
$macro = $this->findMacroAction();
|
||||||
|
return $macro?->getMacro()?->getIdentification()?->getParentCollection()?->getParameterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMacroCollectionUuid(): ?string
|
||||||
|
{
|
||||||
|
$macro = $this->findMacroAction();
|
||||||
|
return $macro?->getMacro()?->getIdentification()?->getParentCollection()?->getParameterUuid()?->getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMacro(string $name, string $uuid, string $collectionName = '--MAIN--', string $collectionUuid = ''): void
|
||||||
|
{
|
||||||
|
$parentCollectionUuid = new UUID();
|
||||||
|
$parentCollectionUuid->setString($collectionUuid);
|
||||||
|
|
||||||
|
$parentCollection = new CollectionElementType();
|
||||||
|
$parentCollection->setParameterName($collectionName);
|
||||||
|
$parentCollection->setParameterUuid($parentCollectionUuid);
|
||||||
|
|
||||||
|
$macroUuid = new UUID();
|
||||||
|
$macroUuid->setString($uuid);
|
||||||
|
|
||||||
|
$identification = new CollectionElementType();
|
||||||
|
$identification->setParameterName($name);
|
||||||
|
$identification->setParameterUuid($macroUuid);
|
||||||
|
$identification->setParentCollection($parentCollection);
|
||||||
|
|
||||||
|
$macroType = new MacroType();
|
||||||
|
$macroType->setIdentification($identification);
|
||||||
|
|
||||||
|
$existingMacroAction = $this->findMacroAction();
|
||||||
|
if ($existingMacroAction !== null) {
|
||||||
|
$existingMacroAction->setType(ActionType::ACTION_TYPE_MACRO);
|
||||||
|
$existingMacroAction->setMacro($macroType);
|
||||||
|
$existingMacroAction->setIsEnabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$macroAction = new Action();
|
||||||
|
$macroAction->setUuid(new UUID());
|
||||||
|
$macroAction->setType(ActionType::ACTION_TYPE_MACRO);
|
||||||
|
$macroAction->setMacro($macroType);
|
||||||
|
$macroAction->setIsEnabled(true);
|
||||||
|
|
||||||
|
$actions = [];
|
||||||
|
foreach ($this->cue->getActions() as $action) {
|
||||||
|
$actions[] = $action;
|
||||||
|
}
|
||||||
|
$actions[] = $macroAction;
|
||||||
|
$this->cue->setActions($actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeMacro(): void
|
||||||
|
{
|
||||||
|
$filteredActions = [];
|
||||||
|
foreach ($this->cue->getActions() as $action) {
|
||||||
|
if ($action->getType() !== ActionType::ACTION_TYPE_MACRO) {
|
||||||
|
$filteredActions[] = $action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cue->setActions($filteredActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasMedia(): bool
|
||||||
|
{
|
||||||
|
return $this->findMediaAction() !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaUrl(): ?string
|
||||||
|
{
|
||||||
|
$media = $this->findMediaAction();
|
||||||
|
return $media?->getMedia()?->getElement()?->getUrl()?->getAbsoluteString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaUuid(): ?string
|
||||||
|
{
|
||||||
|
$media = $this->findMediaAction();
|
||||||
|
return $media?->getMedia()?->getElement()?->getUuid()?->getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaFormat(): ?string
|
||||||
|
{
|
||||||
|
$media = $this->findMediaAction();
|
||||||
|
return $media?->getMedia()?->getElement()?->getMetadata()?->getFormat();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access the underlying protobuf Cue.
|
* Access the underlying protobuf Cue.
|
||||||
*/
|
*/
|
||||||
|
|
@ -143,12 +264,17 @@ class Slide
|
||||||
*/
|
*/
|
||||||
private function getSlideElements(): iterable
|
private function getSlideElements(): iterable
|
||||||
{
|
{
|
||||||
$actions = $this->cue->getActions();
|
$firstAction = null;
|
||||||
if (count($actions) === 0) {
|
foreach ($this->cue->getActions() as $action) {
|
||||||
|
$firstAction = $action;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($firstAction === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$slideType = $actions[0]->getSlide();
|
$slideType = $firstAction->getSlide();
|
||||||
if ($slideType === null) {
|
if ($slideType === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
@ -165,4 +291,26 @@ class Slide
|
||||||
|
|
||||||
return $baseSlide->getElements();
|
return $baseSlide->getElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function findMacroAction(): ?Action
|
||||||
|
{
|
||||||
|
foreach ($this->cue->getActions() as $action) {
|
||||||
|
if ($action->getType() === ActionType::ACTION_TYPE_MACRO) {
|
||||||
|
return $action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findMediaAction(): ?Action
|
||||||
|
{
|
||||||
|
foreach ($this->cue->getActions() as $action) {
|
||||||
|
if ($action->getType() === ActionType::ACTION_TYPE_MEDIA) {
|
||||||
|
return $action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
198
php/tests/SlideExtendedTest.php
Normal file
198
php/tests/SlideExtendedTest.php
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace ProPresenter\Parser\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ProPresenter\Parser\Group;
|
||||||
|
use ProPresenter\Parser\ProFileReader;
|
||||||
|
use ProPresenter\Parser\ProFileWriter;
|
||||||
|
use ProPresenter\Parser\Slide;
|
||||||
|
use ProPresenter\Parser\Song;
|
||||||
|
|
||||||
|
class SlideExtendedTest extends TestCase
|
||||||
|
{
|
||||||
|
private const TEST_WITH_MACRO = '/Users/thorsten/AI/propresenter-work/ref/TestMitMakro.pro';
|
||||||
|
private const TEST_WITH_MEDIA_AND_MACRO = '/Users/thorsten/AI/propresenter-work/ref/TestMitBildernUndMakro.pro';
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testCopyrightSlideHasMacro(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'COPYRIGHT', 0);
|
||||||
|
|
||||||
|
$this->assertTrue($slide->hasMacro());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testMacroNameAndUuid(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'COPYRIGHT', 0);
|
||||||
|
|
||||||
|
$this->assertSame('Lied 1.Folie', $slide->getMacroName());
|
||||||
|
$this->assertSame('20C1DFDE-0FB6-49E5-B90C-E6608D427212', $slide->getMacroUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testMacroCollectionNameAndUuid(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'COPYRIGHT', 0);
|
||||||
|
|
||||||
|
$this->assertSame('--MAIN--', $slide->getMacroCollectionName());
|
||||||
|
$this->assertSame('8D02FC57-83F8-4042-9B90-81C229728426', $slide->getMacroCollectionUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testRegularSlideHasNoMacro(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'Verse 1', 0);
|
||||||
|
|
||||||
|
$this->assertFalse($slide->hasMacro());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testSetMacroOnSlide(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'Verse 1', 0);
|
||||||
|
|
||||||
|
$slide->setMacro('Macro Name', '11111111-2222-3333-4444-555555555555', 'Collection Name', 'AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE');
|
||||||
|
|
||||||
|
$this->assertTrue($slide->hasMacro());
|
||||||
|
$this->assertSame('Macro Name', $slide->getMacroName());
|
||||||
|
$this->assertSame('11111111-2222-3333-4444-555555555555', $slide->getMacroUuid());
|
||||||
|
$this->assertSame('Collection Name', $slide->getMacroCollectionName());
|
||||||
|
$this->assertSame('AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE', $slide->getMacroCollectionUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testRemoveMacro(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'Verse 1', 0);
|
||||||
|
|
||||||
|
$slide->setMacro('Macro Name', '11111111-2222-3333-4444-555555555555');
|
||||||
|
$this->assertTrue($slide->hasMacro());
|
||||||
|
|
||||||
|
$slide->removeMacro();
|
||||||
|
$this->assertFalse($slide->hasMacro());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testSetAndRemoveMacroRoundTrip(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MACRO);
|
||||||
|
$slide = self::getSlideByGroupName($song, 'Verse 1', 0);
|
||||||
|
|
||||||
|
$slide->setMacro('Round Trip Macro', 'AAAAAAAA-1111-2222-3333-BBBBBBBBBBBB', '--MAIN--', '8D02FC57-83F8-4042-9B90-81C229728426');
|
||||||
|
|
||||||
|
$tempPath = sys_get_temp_dir() . '/propresenter-slide-extended-' . uniqid('', true) . '.pro';
|
||||||
|
try {
|
||||||
|
ProFileWriter::write($song, $tempPath);
|
||||||
|
|
||||||
|
$readBack = ProFileReader::read($tempPath);
|
||||||
|
$readBackSlide = self::getSlideByGroupName($readBack, 'Verse 1', 0);
|
||||||
|
|
||||||
|
$this->assertTrue($readBackSlide->hasMacro());
|
||||||
|
$this->assertSame('Round Trip Macro', $readBackSlide->getMacroName());
|
||||||
|
$this->assertSame('AAAAAAAA-1111-2222-3333-BBBBBBBBBBBB', $readBackSlide->getMacroUuid());
|
||||||
|
|
||||||
|
$readBackSlide->removeMacro();
|
||||||
|
$this->assertFalse($readBackSlide->hasMacro());
|
||||||
|
} finally {
|
||||||
|
@unlink($tempPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testImageSlideHasMedia(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[0];
|
||||||
|
|
||||||
|
$this->assertTrue($slide->hasMedia());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testMediaUrlAndFormat(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[0];
|
||||||
|
|
||||||
|
$this->assertStringContainsString('file://', (string) $slide->getMediaUrl());
|
||||||
|
$this->assertSame('JPG', $slide->getMediaFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testImageSlideHasNoText(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[0];
|
||||||
|
|
||||||
|
$this->assertSame('', $slide->getPlainText());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testSlideWithLabel(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[1];
|
||||||
|
|
||||||
|
$this->assertSame('Seniorennachmittag März.jpg', $slide->getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testSlideWithoutLabel(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[0];
|
||||||
|
|
||||||
|
$this->assertSame('', $slide->getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testImageSlideWithMacro(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[1];
|
||||||
|
|
||||||
|
$this->assertTrue($slide->hasMacro());
|
||||||
|
$this->assertSame('1:1 - Beamer & Stream', $slide->getMacroName());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function testSetLabel(): void
|
||||||
|
{
|
||||||
|
$song = self::readSong(self::TEST_WITH_MEDIA_AND_MACRO);
|
||||||
|
$slide = $song->getSlides()[1];
|
||||||
|
|
||||||
|
$slide->setLabel('New Label');
|
||||||
|
|
||||||
|
$this->assertSame('New Label', $slide->getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function readSong(string $path): Song
|
||||||
|
{
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
self::markTestSkipped('Reference file not found: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProFileReader::read($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSlideByGroupName(Song $song, string $groupName, int $slideIndex): Slide
|
||||||
|
{
|
||||||
|
$group = $song->getGroupByName($groupName);
|
||||||
|
self::assertInstanceOf(Group::class, $group, 'Group not found: ' . $groupName);
|
||||||
|
|
||||||
|
$slides = $song->getSlidesForGroup($group);
|
||||||
|
self::assertArrayHasKey($slideIndex, $slides, 'Slide index not found in group: ' . $groupName);
|
||||||
|
|
||||||
|
return $slides[$slideIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue