fix(generator): complete media action with name, audio, and image properties

This commit is contained in:
Thorsten Bus 2026-03-30 08:12:48 +02:00
parent 7cda7e7736
commit 82a9673874
2 changed files with 190 additions and 2 deletions

View file

@ -9,13 +9,17 @@ use Rv\Data\Action\ActionType;
use Rv\Data\Action\LayerType;
use Rv\Data\Action\MacroType;
use Rv\Data\Action\MediaType;
use Rv\Data\Action\MediaType\Audio;
use Rv\Data\Action\SlideType;
use Rv\Data\AlphaType;
use Rv\Data\ApplicationInfo;
use Rv\Data\ApplicationInfo\Application;
use Rv\Data\ApplicationInfo\Platform;
use Rv\Data\Color;
use Rv\Data\CollectionElementType;
use Rv\Data\Cue;
use Rv\Data\FileProperties;
use Rv\Data\Graphics\EdgeInsets;
use Rv\Data\Graphics\Element as GraphicsElement;
use Rv\Data\Graphics\Feather;
use Rv\Data\Graphics\Feather\Style as FeatherStyle;
@ -36,6 +40,7 @@ use Rv\Data\Graphics\Text\VerticalAlignment;
use Rv\Data\Group;
use Rv\Data\HotKey;
use Rv\Data\Media;
use Rv\Data\Media\DrawingProperties;
use Rv\Data\Media\ImageTypeProperties;
use Rv\Data\Media\Metadata;
use Rv\Data\Presentation;
@ -206,9 +211,23 @@ final class ProFileGenerator
$actions = [self::buildSlideAction($slideType)];
if (isset($slideData['media'])) {
// Derive name from label OR filename without extension
$mediaName = $slideData['label'] ?? null;
if ($mediaName === null) {
$basename = basename((string) $slideData['media']);
// Strip query string and fragment
$basename = strtok($basename, '?#') ?: $basename;
// Remove extension
$dotPos = strrpos($basename, '.');
$mediaName = $dotPos !== false ? substr($basename, 0, $dotPos) : $basename;
}
$actions[] = self::buildMediaAction(
(string) $slideData['media'],
(string) ($slideData['format'] ?? 'JPG'),
$mediaName,
(int) ($slideData['mediaWidth'] ?? 0),
(int) ($slideData['mediaHeight'] ?? 0),
);
}
@ -262,7 +281,7 @@ final class ProFileGenerator
return $action;
}
private static function buildMediaAction(string $absoluteUrl, string $format): Action
private static function buildMediaAction(string $absoluteUrl, string $format, ?string $name = null, int $imageWidth = 0, int $imageHeight = 0): Action
{
$url = new URL();
$url->setAbsoluteString($absoluteUrl);
@ -272,15 +291,47 @@ final class ProFileGenerator
$metadata = new Metadata();
$metadata->setFormat($format);
// Build the image type properties with drawing + file
$naturalSize = new Size();
$naturalSize->setWidth($imageWidth);
$naturalSize->setHeight($imageHeight);
$customBoundsOrigin = new Point();
$customBoundsSize = new Size();
$customImageBounds = new Rect();
$customImageBounds->setOrigin($customBoundsOrigin);
$customImageBounds->setSize($customBoundsSize);
$cropInsets = new EdgeInsets();
$drawing = new DrawingProperties();
$drawing->setNaturalSize($naturalSize);
$drawing->setCustomImageBounds($customImageBounds);
$drawing->setCropInsets($cropInsets);
$drawing->setAlphaType(AlphaType::ALPHA_TYPE_STRAIGHT);
$fileLocalUrl = new URL();
$fileLocalUrl->setAbsoluteString($absoluteUrl);
$fileLocalUrl->setLocal(self::buildLocalRelativePath($absoluteUrl));
$fileLocalUrl->setPlatform(UrlPlatform::PLATFORM_MACOS);
$fileProperties = new FileProperties();
$fileProperties->setLocalUrl($fileLocalUrl);
$imageTypeProperties = new ImageTypeProperties();
$imageTypeProperties->setDrawing($drawing);
$imageTypeProperties->setFile($fileProperties);
$mediaElement = new Media();
$mediaElement->setUuid(self::newUuid());
$mediaElement->setUrl($url);
$mediaElement->setMetadata($metadata);
$mediaElement->setImage(new ImageTypeProperties());
$mediaElement->setImage($imageTypeProperties);
$mediaType = new MediaType();
$mediaType->setLayerType(LayerType::LAYER_TYPE_FOREGROUND);
$mediaType->setElement($mediaElement);
$mediaType->setAudio(new Audio());
$action = new Action();
$action->setUuid(self::newUuid());
@ -288,6 +339,10 @@ final class ProFileGenerator
$action->setMedia($mediaType);
$action->setIsEnabled(true);
if ($name !== null) {
$action->setName($name);
}
return $action;
}

View file

@ -881,4 +881,137 @@ class ProFileGeneratorTest extends TestCase
$this->assertSame(1, $url->getLocal()->getRoot()); // ROOT_BOOT_VOLUME = 1
$this->assertSame('tmp/test-image.jpg', $url->getLocal()->getPath());
}
#[Test]
public function testMediaActionHasNameFromFilename(): void
{
$song = ProFileGenerator::generate(
'Media Name Test',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
[
'text' => 'x',
'media' => 'file:///Users/test/AI/Media/test-image.png',
'format' => 'png',
'mediaWidth' => 200,
'mediaHeight' => 150,
],
],
],
],
[
['name' => 'n', 'groupNames' => ['V1']],
],
);
$mediaAction = $song->getPresentation()->getCues()[0]->getActions()[1];
$this->assertSame('test-image', $mediaAction->getName());
}
#[Test]
public function testMediaActionHasNameFromLabel(): void
{
$song = ProFileGenerator::generate(
'Media Label Name Test',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
[
'text' => 'x',
'media' => 'file:///Users/test/AI/Media/test-image.png',
'format' => 'png',
'label' => 'My Custom Label',
],
],
],
],
[
['name' => 'n', 'groupNames' => ['V1']],
],
);
$mediaAction = $song->getPresentation()->getCues()[0]->getActions()[1];
$this->assertSame('My Custom Label', $mediaAction->getName());
}
#[Test]
public function testMediaActionHasAudioOnMediaType(): void
{
$song = ProFileGenerator::generate(
'Media Audio Test',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
[
'text' => 'x',
'media' => 'file:///Users/test/AI/Media/test-image.png',
'format' => 'png',
],
],
],
],
[
['name' => 'n', 'groupNames' => ['V1']],
],
);
$mediaAction = $song->getPresentation()->getCues()[0]->getActions()[1];
$media = $mediaAction->getMedia();
$this->assertNotNull($media->getAudio());
// Element should still be set (audio oneof doesn't clear element)
$this->assertNotNull($media->getElement());
}
#[Test]
public function testMediaActionHasImageDrawingAndFileProperties(): void
{
$song = ProFileGenerator::generate(
'Media Image Props Test',
[
[
'name' => 'V1',
'color' => [0, 0, 0, 1],
'slides' => [
[
'text' => 'x',
'media' => 'file:///Users/test/AI/Media/test-image.png',
'format' => 'png',
'mediaWidth' => 200,
'mediaHeight' => 150,
],
],
],
],
[
['name' => 'n', 'groupNames' => ['V1']],
],
);
$mediaAction = $song->getPresentation()->getCues()[0]->getActions()[1];
$image = $mediaAction->getMedia()->getElement()->getImage();
$this->assertNotNull($image);
// Verify drawing properties
$this->assertNotNull($image->getDrawing());
$this->assertSame(200.0, $image->getDrawing()->getNaturalSize()->getWidth());
$this->assertSame(150.0, $image->getDrawing()->getNaturalSize()->getHeight());
$this->assertNotNull($image->getDrawing()->getCustomImageBounds());
$this->assertNotNull($image->getDrawing()->getCustomImageBounds()->getOrigin());
$this->assertNotNull($image->getDrawing()->getCustomImageBounds()->getSize());
$this->assertNotNull($image->getDrawing()->getCropInsets());
$this->assertSame(1, $image->getDrawing()->getAlphaType()); // ALPHA_TYPE_STRAIGHT = 1
// Verify file properties
$this->assertNotNull($image->getFile());
$this->assertNotNull($image->getFile()->getLocalUrl());
$this->assertSame('file:///Users/test/AI/Media/test-image.png', $image->getFile()->getLocalUrl()->getAbsoluteString());
}
}