Add full IO support for every global ProPresenter library file plus theme folders, and extend the existing Labels/Macros readers with exporters and editable accessors so every supported document is now a round-trippable, mutable object. New library readers/writers (each: FileReader, FileWriter, Library wrapper, element wrapper where applicable, CLI tool, tests, doc/api/*.md): - Groups (ProGroupsDocument) + GroupDefinition - ClearGroups (ClearGroupsDocument) + ClearGroupDefinition - CCLI (CCLIDocument) - Messages (MessageDocument) + Message - Timers (TimersDocument + Clock) + Timer - Stage (Stage.Document) + StageLayout - Workspace (ProPresenterWorkspace) + Screen - Props (PropDocument) + Prop - TestPatterns (TestPatternDocument) - Calendar (new CalendarDocument) + CalendarEvent - KeyMappings (new KeyMappingsDocument) + KeyMapping - CommunicationDevices (JSON file) + CommunicationDevice - Theme bundles (Template.Document folder + Assets/) + ThemeBundle/Slide/Asset Extensions to existing modules: - LabelsFileWriter; Label and LabelLibrary gain setters, addLabel, removeLabel, setColor / setColorHex helpers - MacrosFileWriter; Macro/MacroCollection/MacroLibrary gain UUID, name, color, image_type, image_data, trigger_on_startup setters plus add/remove for macros and collections Two new minimal proto schemas were defined for documents that lacked upstream definitions: - proto/calendar.proto - CalendarDocument with Event entries, raw bytes for the action/macro sub-messages so the schema can evolve - proto/keyMappings.proto - KeyMappingsDocument with ApplicationInfo and a forward-looking Mapping message (sample only carries the info) The Theme file turned out to be a regular Rv\Data\Template\Document, so no new proto was required for theme content; ThemeBundle layers folder + Assets/ handling on top in the same spirit as PresentationBundle. GroupDefinition is intentionally distinct from the existing Group class (which wraps song-level CueGroup) to avoid breaking song APIs. Verified with the full PHPUnit suite: 370 tests, 9200 assertions, all green; LSP diagnostics clean across src/. The unmodified reference samples for Labels, Groups, ClearGroups, TestPatterns, Calendar and KeyMappings round-trip byte-for-byte; the others round-trip with the same byte length (PHP protobuf is not canonically deterministic but re-write-after-write stabilises). doc/INDEX.md, doc/keywords.md and AGENTS.md updated so every new module is discoverable from the top level.
4.9 KiB
Labels Library API
PHP module for reading the global ProPresenter
Labelsfile (raw protobuf, no extension) and exposing each label's name and UI color.
Quick Reference
use ProPresenter\Parser\LabelsFileReader;
use ProPresenter\Parser\LabelsFileWriter;
$library = LabelsFileReader::read('/path/to/Labels');
foreach ($library->getLabels() as $label) {
$label->getName(); // "KeyVisual Beamer"
$label->hasColor(); // bool
$label->getColor(); // ['r'=>0.0,'g'=>0.408,'b'=>0.702,'a'=>1.0] | null
$label->getColorHex(); // "#0068B3" | null
}
// Modify and persist
$library->addLabel('NewLabel', ['r' => 1.0, 'g' => 0.5, 'b' => 0.0]);
$beamer = $library->getLabelByName('KeyVisual Beamer');
$beamer?->setColorHex('#FF8800');
$library->removeLabel('Wiederholen');
LabelsFileWriter::write($library, '/path/to/Labels');
File Layout
The Labels file is the protobuf-serialised
ProLabelsDocument:
| Field | Type | Description |
|---|---|---|
labels |
repeated Action.Label |
Definitions: text + optional color |
Each Action.Label carries:
| Field | Type | Description |
|---|---|---|
text |
string | Display name (exposed as getName() on the wrapper) |
color |
Color (optional) |
RGBA float channels in 0..1; absent for system / "no color" labels |
Labels are identified by name only — there is no UUID. Slides reference
labels by name from inside .pro files.
Reading
use ProPresenter\Parser\LabelsFileReader;
$library = LabelsFileReader::read('/Users/me/.../Labels');
Throws InvalidArgumentException for missing files and RuntimeException for
empty / unreadable files.
Writing
use ProPresenter\Parser\LabelsFileWriter;
LabelsFileWriter::write($library, '/Users/me/.../Labels');
Serialises the underlying ProLabelsDocument to bytes. The unmodified
reference sample round-trips byte-for-byte.
LabelLibrary
Top-level wrapper around Rv\Data\ProLabelsDocument. Indexes labels by name
for fast lookup.
$library->getLabels(); // Label[]
$library->count(); // int
$library->getLabelByName('Szene 1'); // ?Label (case-sensitive)
$library->findLabelByName('szene 1'); // ?Label (case-insensitive)
$library->addLabel('NewLabel', ['r'=>1, 'g'=>0, 'b'=>0]); // ?Label
$library->removeLabel('OldLabel'); // bool
$library->getDocument(); // \Rv\Data\ProLabelsDocument
If the same name appears more than once in the source document the first
occurrence wins for both lookup helpers; every entry is preserved in
getLabels() in document order.
Label
$label->getName(); // "KeyVisual Beamer" (proto field is `text`)
$label->setName('Renamed'); // self
$label->hasColor(); // bool — was a Color message present?
$label->getColor(); // ['r'=>..,'g'=>..,'b'=>..,'a'=>..] | null
$label->getColorHex(); // "#RRGGBB" uppercase, alpha dropped, or null
$label->setColor(['r'=>1, 'g'=>0, 'b'=>0]); // self
$label->setColor(null); // clears the color (UI falls back to default)
$label->setColorHex('#FF8800'); // accepts #RRGGBB or #RRGGBBAA
$label->getProto(); // \Rv\Data\Action\Label (raw protobuf)
Color channels are floats in 0..1 as ProPresenter stores them. getColorHex()
clamps and rounds each channel to 8 bits before formatting.
A label can legitimately exist without a color message. Treat that as
"use the default UI color", not as black. The reference sample's first four
labels (Leere Folie, Instrumental, Wiederholen, Gesprochenes Wort)
hit this case.
CLI Tool
php bin/parse-labels.php /path/to/Labels
Output:
Labels (15):
[1] Leere Folie :: (no color)
[2] Instrumental :: (no color)
[3] Wiederholen :: (no color)
[4] Gesprochenes Wort :: (no color)
[5] KeyVisual Stream & Beamer mit Countdown :: #CC298B rgba(0.800, 0.161, 0.545, 1.000)
[6] KeyVisual Stream & Beamer mit Jingle :: #7600CC rgba(0.463, 0.000, 0.800, 1.000)
...
Key Files
| File | Purpose |
|---|---|
src/LabelLibrary.php |
Document-level wrapper with name lookups + add / remove helpers |
src/Label.php |
Single label wrapper (name, color, hex) with setters |
src/LabelsFileReader.php |
Reads the Labels file |
src/LabelsFileWriter.php |
Writes the Labels file |
bin/parse-labels.php |
CLI tool |
proto/labels.proto |
Protobuf schema (just imports Action.Label) |
proto/action.proto |
Defines the inner Action.Label message |
generated/Rv/Data/ProLabelsDocument.php |
Generated message class |
generated/Rv/Data/Action/Label.php |
Generated label message class |
Scope Notes
Editing slide-side label references on .pro files (cross-document fan-out)
and syncing labels across devices are out of scope; this module only covers
the global Labels document.