docs: prepare project for open-source release on GitHub
- Add MIT LICENSE (Thorsten Buss) with attribution to the upstream MIT-licensed greyshirtguy/ProPresenter7-Proto definitions. - Add comprehensive README.md: badges, feature matrix, install, seven runnable getting-started examples (read/modify/generate songs, playlists, bundles, global libraries), CLI tool reference, documentation index, project structure, caveats. - Update composer.json with package name (bussnet/propresenter7-php-api), MIT license, keywords, author, homepage, support URLs, dev autoload, and a `composer test` script. - Polish doc/INDEX.md, doc/keywords.md, and doc/CONTRIBUTING.md so they read well for both humans and AI assistants; remove README-duplicate content from INDEX.md and link to the top-level README instead. - Expand .gitignore to cover IDE/OS metadata and agent workspaces. All 370 tests still pass (9,200 assertions). README examples #3 and #5 verified end-to-end (generate -> read back -> assert metadata).
This commit is contained in:
parent
9e3e719806
commit
5ac27d676c
28
.gitignore
vendored
28
.gitignore
vendored
|
|
@ -1,4 +1,26 @@
|
||||||
.sisyphus
|
# Composer
|
||||||
.php-cs-fixer.cache
|
/vendor/
|
||||||
|
composer.phar
|
||||||
|
|
||||||
|
# PHPUnit
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
vendor/
|
/build/
|
||||||
|
/coverage/
|
||||||
|
|
||||||
|
# PHP CS Fixer
|
||||||
|
.php-cs-fixer.cache
|
||||||
|
.php_cs.cache
|
||||||
|
|
||||||
|
# IDE / editor metadata
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Internal scratch / agent workspaces
|
||||||
|
.sisyphus/
|
||||||
|
.w/
|
||||||
|
|
|
||||||
29
LICENSE
Normal file
29
LICENSE
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Thorsten Buss
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Third-Party Notices
|
||||||
|
|
||||||
|
This project bundles `.proto` files derived from
|
||||||
|
[greyshirtguy/ProPresenter7-Proto](https://github.com/greyshirtguy/ProPresenter7-Proto)
|
||||||
|
(v7.16.2), which is also distributed under the MIT License.
|
||||||
523
README.md
523
README.md
|
|
@ -0,0 +1,523 @@
|
||||||
|
# ProPresenter 7 PHP API
|
||||||
|
|
||||||
|
> A PHP library to **read, modify, and generate** [ProPresenter 7](https://renewedvision.com/propresenter/) files — songs, playlists, bundles, themes, and global library files.
|
||||||
|
|
||||||
|
[](https://www.php.net/)
|
||||||
|
[](LICENSE)
|
||||||
|
[](#development)
|
||||||
|
[](https://protobuf.dev/)
|
||||||
|
|
||||||
|
ProPresenter 7 stores its data in protobuf-encoded binary files (with ZIP wrappers for playlists and bundles). This library decodes those formats into idiomatic PHP objects, lets you modify them, and writes them back out — with full round-trip fidelity for global library files and verified compatibility with PP7 for songs and bundles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Features](#features)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Getting Started](#getting-started)
|
||||||
|
- [1. Read a song (`.pro`)](#1-read-a-song-pro)
|
||||||
|
- [2. Modify and save a song](#2-modify-and-save-a-song)
|
||||||
|
- [3. Generate a song from scratch](#3-generate-a-song-from-scratch)
|
||||||
|
- [4. Read a playlist (`.proplaylist`)](#4-read-a-playlist-proplaylist)
|
||||||
|
- [5. Generate a playlist](#5-generate-a-playlist)
|
||||||
|
- [6. Work with a `.probundle`](#6-work-with-a-probundle)
|
||||||
|
- [7. Read a global library file](#7-read-a-global-library-file)
|
||||||
|
- [CLI Tools](#cli-tools)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Project Structure](#project-structure)
|
||||||
|
- [Development](#development)
|
||||||
|
- [Compatibility & Caveats](#compatibility--caveats)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [License](#license)
|
||||||
|
- [Credits](#credits)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### File formats supported
|
||||||
|
|
||||||
|
| Format | Extension | Read | Modify | Generate | Notes |
|
||||||
|
|--------|-----------|:----:|:------:|:--------:|-------|
|
||||||
|
| Song | `.pro` | ✅ | ✅ | ✅ | Lyrics, groups, slides, arrangements, translations, CCLI metadata, macros, media |
|
||||||
|
| Playlist | `.proplaylist` | ✅ | ✅ | ✅ | ZIP64 archive, embedded songs, headers, placeholders |
|
||||||
|
| Bundle | `.probundle` | ✅ | ✅ | ✅ | ZIP archive containing a song + flat media assets |
|
||||||
|
| Theme | folder | ✅ | ✅ | ✅ | `Theme` protobuf + `Assets/` directory |
|
||||||
|
| Macros | `Macros` | ✅ | ✅ | — | Macros + collections |
|
||||||
|
| Labels | `Labels` | ✅ | ✅ | — | Slide labels with optional UI colors |
|
||||||
|
| Groups | `Groups` | ✅ | ✅ | — | Library groups (UUID, color, hot keys) |
|
||||||
|
| ClearGroups | `ClearGroups` | ✅ | ✅ | — | Clear-action groups |
|
||||||
|
| CCLI | `CCLI` | ✅ | ✅ | — | License, copyright template |
|
||||||
|
| Messages | `Messages` | ✅ | ✅ | — | Lower-third / overlay messages |
|
||||||
|
| Timers | `Timers` | ✅ | ✅ | — | Timer definitions + clock format |
|
||||||
|
| Stage | `Stage` | ✅ | ✅ | — | Stage display layouts |
|
||||||
|
| Workspace | `Workspace` | ✅ | ✅ | — | Screens, looks, masks, audio/video inputs |
|
||||||
|
| Props | `Props` | ✅ | ✅ | — | Prop cues + transitions |
|
||||||
|
| TestPatterns | `TestPatterns` | ✅ | ✅ | — | Test pattern overrides |
|
||||||
|
| Calendar | `Calendar` | ✅ | ✅ | — | Scheduled events firing macros |
|
||||||
|
| KeyMappings | `KeyMappings` | ✅ | ✅ | — | Custom hot-key bindings |
|
||||||
|
| CommunicationDevices | JSON | ✅ | ✅ | — | MIDI / serial / OSC bindings |
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- **High-level wrappers** — work with `Song`, `Group`, `Slide`, `Arrangement`, `PlaylistArchive` etc. instead of raw protobuf classes.
|
||||||
|
- **RTF text extraction** — `Slide::getPlainText()` returns clean text from ProPresenter's CocoaRTF, including German umlauts and Unicode.
|
||||||
|
- **Translation-aware** — read and write multi-language slides (`hasTranslation()`, `getTranslation()`).
|
||||||
|
- **ZIP64 repair** — automatically fixes ProPresenter's 98-byte ZIP64 header bug on read.
|
||||||
|
- **Generate from scratch** — build complete `.pro` and `.proplaylist` files programmatically with media references.
|
||||||
|
- **18 CLI tools** — quickly inspect any ProPresenter file from the command line.
|
||||||
|
- **370 tests, 9,200+ assertions** — verified against 169 real-world reference songs from production worship environments.
|
||||||
|
- **Comprehensive docs** — every API and binary format is documented in [`doc/`](doc/).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **PHP 8.4** or higher
|
||||||
|
- [`google/protobuf`](https://github.com/protocolbuffers/protobuf-php) (installed via Composer)
|
||||||
|
- [`ext-zip`](https://www.php.net/manual/en/book.zip.php) for `.proplaylist` and `.probundle` files (bundled with most PHP distributions)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require bussnet/propresenter7-php-api
|
||||||
|
```
|
||||||
|
|
||||||
|
Or clone the repository to develop locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/bussnet/propresenter7-php-api.git
|
||||||
|
cd propresenter7-php-api
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
All examples assume Composer's autoloader is loaded:
|
||||||
|
|
||||||
|
```php
|
||||||
|
require 'vendor/autoload.php';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1. Read a song (`.pro`)
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProFileReader;
|
||||||
|
|
||||||
|
$song = ProFileReader::read('path/to/Amazing Grace.pro');
|
||||||
|
|
||||||
|
echo $song->getName() . "\n"; // "Amazing Grace"
|
||||||
|
echo $song->getCcliAuthor() . "\n"; // "John Newton"
|
||||||
|
echo $song->getCcliCopyrightYear() . "\n"; // 1779
|
||||||
|
|
||||||
|
// Walk groups → slides → text
|
||||||
|
foreach ($song->getGroups() as $group) {
|
||||||
|
echo "[{$group->getName()}]\n";
|
||||||
|
|
||||||
|
foreach ($song->getSlidesForGroup($group) as $slide) {
|
||||||
|
echo " " . $slide->getPlainText() . "\n";
|
||||||
|
|
||||||
|
if ($slide->hasTranslation()) {
|
||||||
|
echo " → " . $slide->getTranslation()->getPlainText() . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve an arrangement to a flat list of groups (in performance order)
|
||||||
|
$arrangement = $song->getArrangements()[0];
|
||||||
|
foreach ($song->getGroupsForArrangement($arrangement) as $group) {
|
||||||
|
echo $group->getName() . " → ";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Modify and save a song
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProFileReader;
|
||||||
|
use ProPresenter\Parser\ProFileWriter;
|
||||||
|
|
||||||
|
$song = ProFileReader::read('input.pro');
|
||||||
|
|
||||||
|
// Update CCLI metadata
|
||||||
|
$song->setName('Amazing Grace (My Chains Are Gone)');
|
||||||
|
$song->setCcliPublisher('Public Domain');
|
||||||
|
$song->setCcliCopyrightYear(2006);
|
||||||
|
|
||||||
|
// Rename a group
|
||||||
|
$song->getGroupByName('Verse 1')?->setName('Strophe 1');
|
||||||
|
|
||||||
|
// Add a label to the first slide
|
||||||
|
$song->getSlides()[0]->setLabel('Intro');
|
||||||
|
|
||||||
|
ProFileWriter::write($song, 'output.pro');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Generate a song from scratch
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProFileGenerator;
|
||||||
|
|
||||||
|
ProFileGenerator::generateAndWrite(
|
||||||
|
'amazing-grace.pro',
|
||||||
|
'Amazing Grace',
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'Verse 1',
|
||||||
|
'color' => [0.13, 0.59, 0.95, 1.0], // RGBA floats (0..1)
|
||||||
|
'slides' => [
|
||||||
|
['text' => "Amazing grace, how sweet the sound\nThat saved a wretch like me"],
|
||||||
|
[
|
||||||
|
'text' => 'I once was lost, but now am found',
|
||||||
|
'translation' => 'Ich war verloren, doch jetzt gefunden',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Chorus',
|
||||||
|
'color' => [0.95, 0.27, 0.27, 1.0],
|
||||||
|
'slides' => [
|
||||||
|
['text' => 'My chains are gone, I have been set free'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
['name' => 'normal', 'groupNames' => ['Verse 1', 'Chorus', 'Verse 1', 'Chorus']],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'author' => 'John Newton',
|
||||||
|
'song_title' => 'Amazing Grace',
|
||||||
|
'copyright_year' => 1779,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Read a playlist (`.proplaylist`)
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProPlaylistReader;
|
||||||
|
|
||||||
|
$archive = ProPlaylistReader::read('Sunday Service.proplaylist');
|
||||||
|
|
||||||
|
echo $archive->getName() . "\n";
|
||||||
|
|
||||||
|
foreach ($archive->getEntries() as $entry) {
|
||||||
|
echo match ($entry->getType()) {
|
||||||
|
'header' => "── {$entry->getName()} ──\n",
|
||||||
|
'presentation' => " ♪ {$entry->getName()} (arr: " . ($entry->getArrangementName() ?? 'default') . ")\n",
|
||||||
|
'placeholder' => " · {$entry->getName()} (TBD)\n",
|
||||||
|
default => " ? {$entry->getName()}\n",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lazily parse embedded .pro files
|
||||||
|
if ($entry->getType() === 'presentation') {
|
||||||
|
$song = $archive->getEmbeddedSong($entry);
|
||||||
|
if ($song !== null) {
|
||||||
|
echo " → " . count($song->getSlides()) . " slides\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Generate a playlist
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProPlaylistGenerator;
|
||||||
|
|
||||||
|
ProPlaylistGenerator::generateAndWrite(
|
||||||
|
'sunday-service.proplaylist',
|
||||||
|
'Sunday Service',
|
||||||
|
[
|
||||||
|
['type' => 'header', 'name' => 'Worship', 'color' => [0.95, 0.27, 0.27, 1.0]],
|
||||||
|
['type' => 'presentation', 'name' => 'Amazing Grace', 'path' => 'file:///Songs/amazing-grace.pro', 'arrangement' => 'normal'],
|
||||||
|
['type' => 'presentation', 'name' => 'Oceans', 'path' => 'file:///Songs/oceans.pro'],
|
||||||
|
['type' => 'header', 'name' => 'Sermon'],
|
||||||
|
['type' => 'placeholder', 'name' => 'Sermon notes'],
|
||||||
|
],
|
||||||
|
['notes' => 'Sunday morning service'],
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Work with a `.probundle`
|
||||||
|
|
||||||
|
A `.probundle` is a ZIP archive containing a single `.pro` file plus its referenced media — perfect for sharing presentations between machines.
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\ProBundleReader;
|
||||||
|
use ProPresenter\Parser\ProBundleWriter;
|
||||||
|
use ProPresenter\Parser\PresentationBundle;
|
||||||
|
use ProPresenter\Parser\ProFileGenerator;
|
||||||
|
|
||||||
|
// Read
|
||||||
|
$bundle = ProBundleReader::read('Christmas Slides.probundle');
|
||||||
|
echo $bundle->getName() . "\n";
|
||||||
|
echo $bundle->getMediaFileCount() . " media files\n";
|
||||||
|
|
||||||
|
foreach ($bundle->getMediaFiles() as $filename => $bytes) {
|
||||||
|
echo " $filename: " . strlen($bytes) . " bytes\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a new bundle (media uses ROOT_CURRENT_RESOURCE → portable across machines)
|
||||||
|
$song = ProFileGenerator::generate(
|
||||||
|
'My Slides',
|
||||||
|
[[
|
||||||
|
'name' => 'Background',
|
||||||
|
'color' => [0.2, 0.2, 0.2, 1.0],
|
||||||
|
'slides' => [[
|
||||||
|
'media' => 'background.png',
|
||||||
|
'format' => 'png',
|
||||||
|
'label' => 'background.png',
|
||||||
|
'bundleRelative' => true,
|
||||||
|
]],
|
||||||
|
]],
|
||||||
|
[['name' => 'normal', 'groupNames' => ['Background']]],
|
||||||
|
);
|
||||||
|
|
||||||
|
$bundle = new PresentationBundle(
|
||||||
|
$song,
|
||||||
|
'My Slides.pro',
|
||||||
|
['background.png' => file_get_contents('background.png')],
|
||||||
|
);
|
||||||
|
|
||||||
|
ProBundleWriter::write($bundle, 'my-slides.probundle');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Read a global library file
|
||||||
|
|
||||||
|
ProPresenter stores its global library in extension-less protobuf files inside the user library folder. Each is exposed through a dedicated reader/writer:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use ProPresenter\Parser\MacrosFileReader;
|
||||||
|
use ProPresenter\Parser\MacrosFileWriter;
|
||||||
|
|
||||||
|
$library = MacrosFileReader::read('/path/to/Macros');
|
||||||
|
|
||||||
|
foreach ($library->getMacros() as $macro) {
|
||||||
|
echo $macro->getName() . " — " . $macro->getUuid() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a macro programmatically
|
||||||
|
$library->addMacro('Service Start', '00000000-0000-0000-0000-000000000001');
|
||||||
|
$library->getMacroByName('Service Start')?->setColor(['r' => 0.0, 'g' => 0.5, 'b' => 1.0]);
|
||||||
|
|
||||||
|
MacrosFileWriter::write($library, '/path/to/Macros');
|
||||||
|
```
|
||||||
|
|
||||||
|
The same `Reader::read()` / `Writer::write()` pattern applies to every global library file. See [doc/api/](doc/api/) for the full set.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLI Tools
|
||||||
|
|
||||||
|
Every supported file type ships with an inspector script in [`bin/`](bin/):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/parse-song.php path/to/song.pro
|
||||||
|
php bin/parse-playlist.php path/to/playlist.proplaylist
|
||||||
|
php bin/parse-theme.php path/to/ThemeFolder
|
||||||
|
php bin/parse-macros.php ~/Library/.../Macros
|
||||||
|
php bin/parse-labels.php ~/Library/.../Labels
|
||||||
|
php bin/parse-groups.php ~/Library/.../Groups
|
||||||
|
php bin/parse-clear-groups.php ~/Library/.../ClearGroups
|
||||||
|
php bin/parse-ccli.php ~/Library/.../CCLI
|
||||||
|
php bin/parse-messages.php ~/Library/.../Messages
|
||||||
|
php bin/parse-timers.php ~/Library/.../Timers
|
||||||
|
php bin/parse-stage.php ~/Library/.../Stage
|
||||||
|
php bin/parse-workspace.php ~/Library/.../Workspace
|
||||||
|
php bin/parse-props.php ~/Library/.../Props
|
||||||
|
php bin/parse-test-patterns.php ~/Library/.../TestPatterns
|
||||||
|
php bin/parse-calendar.php ~/Library/.../Calendar
|
||||||
|
php bin/parse-key-mappings.php ~/Library/.../KeyMappings
|
||||||
|
php bin/parse-communication-devices.php ~/Library/.../CommunicationDevices
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output for `parse-song.php`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Song: Amazing Grace
|
||||||
|
UUID: A1B2C3D4-...
|
||||||
|
|
||||||
|
CCLI Metadata:
|
||||||
|
Song Title: Amazing Grace
|
||||||
|
Author: John Newton
|
||||||
|
Copyright Year: 1779
|
||||||
|
Display: yes
|
||||||
|
|
||||||
|
Groups (3):
|
||||||
|
[1] Verse 1 (2 slides)
|
||||||
|
Slide 1: Amazing grace, how sweet the sound / That saved a wretch like me
|
||||||
|
Slide 2: I once was lost, but now am found
|
||||||
|
[2] Chorus (1 slide)
|
||||||
|
Slide 1: My chains are gone, I have been set free
|
||||||
|
...
|
||||||
|
|
||||||
|
Arrangements (1):
|
||||||
|
[1] normal: Verse 1 -> Chorus -> Verse 1 -> Chorus
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Full documentation lives in [`doc/`](doc/) — start with **[doc/INDEX.md](doc/INDEX.md)**.
|
||||||
|
|
||||||
|
### API reference
|
||||||
|
|
||||||
|
| Topic | Document |
|
||||||
|
|-------|----------|
|
||||||
|
| Songs (`.pro`) | [doc/api/song.md](doc/api/song.md) |
|
||||||
|
| Playlists (`.proplaylist`) | [doc/api/playlist.md](doc/api/playlist.md) |
|
||||||
|
| Bundles (`.probundle`) | [doc/api/bundle.md](doc/api/bundle.md) |
|
||||||
|
| Themes (folder) | [doc/api/theme.md](doc/api/theme.md) |
|
||||||
|
| Macros library | [doc/api/macros.md](doc/api/macros.md) |
|
||||||
|
| Labels library | [doc/api/labels.md](doc/api/labels.md) |
|
||||||
|
| Groups library | [doc/api/groups.md](doc/api/groups.md) |
|
||||||
|
| ClearGroups library | [doc/api/clear-groups.md](doc/api/clear-groups.md) |
|
||||||
|
| CCLI settings | [doc/api/ccli.md](doc/api/ccli.md) |
|
||||||
|
| Messages library | [doc/api/messages.md](doc/api/messages.md) |
|
||||||
|
| Timers library | [doc/api/timers.md](doc/api/timers.md) |
|
||||||
|
| Stage layouts | [doc/api/stage.md](doc/api/stage.md) |
|
||||||
|
| Workspace | [doc/api/workspace.md](doc/api/workspace.md) |
|
||||||
|
| Props library | [doc/api/props.md](doc/api/props.md) |
|
||||||
|
| TestPatterns | [doc/api/test-patterns.md](doc/api/test-patterns.md) |
|
||||||
|
| Calendar | [doc/api/calendar.md](doc/api/calendar.md) |
|
||||||
|
| KeyMappings | [doc/api/key-mappings.md](doc/api/key-mappings.md) |
|
||||||
|
| CommunicationDevices | [doc/api/communication-devices.md](doc/api/communication-devices.md) |
|
||||||
|
|
||||||
|
### Binary format specifications
|
||||||
|
|
||||||
|
| Format | Document |
|
||||||
|
|--------|----------|
|
||||||
|
| `.pro` (songs) | [doc/formats/pp_song_spec.md](doc/formats/pp_song_spec.md) |
|
||||||
|
| `.proplaylist` | [doc/formats/pp_playlist_spec.md](doc/formats/pp_playlist_spec.md) |
|
||||||
|
| `.probundle` | [doc/formats/pp_bundle_spec.md](doc/formats/pp_bundle_spec.md) |
|
||||||
|
|
||||||
|
### Search by keyword
|
||||||
|
|
||||||
|
Looking for something specific? Use the keyword index: [doc/keywords.md](doc/keywords.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── bin/ # 18 CLI tools (parse-*.php scripts)
|
||||||
|
├── src/ # PHP source (wrappers, readers, writers, generators)
|
||||||
|
├── generated/ # Auto-generated protobuf PHP classes (Rv\Data\…)
|
||||||
|
├── proto/ # Vendored .proto files (greyshirtguy/ProPresenter7-Proto v7.16.2)
|
||||||
|
├── tests/ # PHPUnit test suite (370 tests)
|
||||||
|
├── doc/
|
||||||
|
│ ├── INDEX.md # Documentation entry point
|
||||||
|
│ ├── keywords.md # Keyword search index
|
||||||
|
│ ├── CONTRIBUTING.md # Documentation guidelines
|
||||||
|
│ ├── api/ # PHP API documentation
|
||||||
|
│ ├── formats/ # Binary file format specifications
|
||||||
|
│ ├── internal/ # Development notes (learnings, decisions, issues)
|
||||||
|
│ └── reference_samples/ # Reference files used by tests (real-world songs)
|
||||||
|
├── composer.json
|
||||||
|
├── phpunit.xml
|
||||||
|
├── LICENSE
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key classes
|
||||||
|
|
||||||
|
| Class | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `ProPresenter\Parser\Song` | Top-level song wrapper (groups + slides + arrangements) |
|
||||||
|
| `ProPresenter\Parser\Group` | Song part (verse, chorus, …) |
|
||||||
|
| `ProPresenter\Parser\Slide` | Single slide with text, label, macro, media |
|
||||||
|
| `ProPresenter\Parser\TextElement` | Text element with RTF + plain-text accessors |
|
||||||
|
| `ProPresenter\Parser\Arrangement` | Group order for a performance |
|
||||||
|
| `ProPresenter\Parser\PlaylistArchive` | `.proplaylist` ZIP wrapper |
|
||||||
|
| `ProPresenter\Parser\PresentationBundle` | `.probundle` ZIP wrapper |
|
||||||
|
| `ProPresenter\Parser\ThemeBundle` | Theme folder wrapper |
|
||||||
|
| `ProPresenter\Parser\ProFileReader` / `Writer` / `Generator` | `.pro` IO |
|
||||||
|
| `ProPresenter\Parser\ProPlaylistReader` / `Writer` / `Generator` | `.proplaylist` IO |
|
||||||
|
| `ProPresenter\Parser\ProBundleReader` / `Writer` | `.probundle` IO |
|
||||||
|
| `ProPresenter\Parser\Zip64Fixer` | Repairs ProPresenter's broken ZIP64 EOCD headers |
|
||||||
|
| `ProPresenter\Parser\RtfExtractor` | Standalone CocoaRTF → plain-text converter |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Running the tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see:
|
||||||
|
|
||||||
|
```text
|
||||||
|
PHPUnit 11.5.55 by Sebastian Bergmann and contributors.
|
||||||
|
|
||||||
|
OK (370 tests, 9200 assertions)
|
||||||
|
```
|
||||||
|
|
||||||
|
The test suite includes:
|
||||||
|
|
||||||
|
- **Unit tests** — every wrapper class
|
||||||
|
- **Integration tests** — readers + writers round-tripping reference files
|
||||||
|
- **Mass validation** — parses 169 real-world `.pro` songs (`tests/MassValidationTest.php`)
|
||||||
|
- **Binary fidelity tests** — verifies byte-perfect round-trips for global library files
|
||||||
|
|
||||||
|
### Reference samples
|
||||||
|
|
||||||
|
Real ProPresenter files used by the tests live in [`doc/reference_samples/`](doc/reference_samples/). They are exported from production worship environments and cover edge cases (translations, missing arrangements, ZIP64 quirks, German Unicode, embedded media).
|
||||||
|
|
||||||
|
### Regenerating sample bundles
|
||||||
|
|
||||||
|
Some test fixtures are generated procedurally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/regen-test-bundles.php
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Compatibility & Caveats
|
||||||
|
|
||||||
|
- **Verified against** ProPresenter 7.16+ on macOS. Files generated by this library open cleanly in ProPresenter 7.
|
||||||
|
- **Round-trip fidelity** — global library files (`Macros`, `Labels`, `Groups`, …) round-trip byte-for-byte. Songs do **not**: ProPresenter's protobuf schema contains undocumented fields that are dropped on re-encode. The library preserves logical content perfectly, but raw bytes will differ. See [doc/internal/issues.md](doc/internal/issues.md) for the gory details.
|
||||||
|
- **ZIP64 quirk** — ProPresenter exports `.proplaylist` and `.probundle` files with a 98-byte ZIP64 header offset bug. `Zip64Fixer` patches this in memory before parsing. Files written by this library use clean standard ZIPs.
|
||||||
|
- **RTF** — slide text is stored as CocoaRTF (Windows-1252 with `\'xx` hex escapes for non-ASCII). `getPlainText()` decodes this; the generator produces clean RTF that PP7 accepts.
|
||||||
|
- **macOS-centric paths** — ProPresenter uses `file://` URLs with absolute paths in some fields. For portable bundles, use `'bundleRelative' => true` on media slides (this sets `ROOT_CURRENT_RESOURCE` so PP7 resolves media relative to the archive).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please:
|
||||||
|
|
||||||
|
1. Open an issue describing the change before sending a PR for anything non-trivial.
|
||||||
|
2. Follow the documentation guidelines in [doc/CONTRIBUTING.md](doc/CONTRIBUTING.md).
|
||||||
|
3. Add a test for any new behavior — TDD is the convention here.
|
||||||
|
4. Run `composer test` before submitting.
|
||||||
|
5. Keep changes focused; avoid unrelated refactors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is released under the [MIT License](LICENSE).
|
||||||
|
|
||||||
|
The bundled `.proto` files in [`proto/`](proto/) are derived from [greyshirtguy/ProPresenter7-Proto](https://github.com/greyshirtguy/ProPresenter7-Proto) v7.16.2, also distributed under the MIT License.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- **[Renewed Vision](https://renewedvision.com/)** — for ProPresenter, an excellent presentation tool.
|
||||||
|
- **[greyshirtguy](https://github.com/greyshirtguy/ProPresenter7-Proto)** — for reverse-engineering the ProPresenter 7 protobuf schema, without which this library would not exist.
|
||||||
|
- **[Google Protocol Buffers](https://protobuf.dev/)** — for the underlying serialization format.
|
||||||
|
|
||||||
|
ProPresenter is a trademark of Renewed Vision, LLC. This project is not affiliated with or endorsed by Renewed Vision.
|
||||||
|
|
@ -1,7 +1,32 @@
|
||||||
{
|
{
|
||||||
"name": "propresenter/parser",
|
"name": "bussnet/propresenter7-php-api",
|
||||||
"description": "ProPresenter song file parser",
|
"description": "PHP library to read, modify, and generate ProPresenter 7 files (.pro songs, .proplaylist, .probundle, themes, and global library files).",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"propresenter",
|
||||||
|
"propresenter7",
|
||||||
|
"presentation",
|
||||||
|
"worship",
|
||||||
|
"church",
|
||||||
|
"protobuf",
|
||||||
|
"parser",
|
||||||
|
"ccli",
|
||||||
|
"pro-file",
|
||||||
|
"proplaylist",
|
||||||
|
"probundle"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/bussnet/propresenter7-php-api",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/bussnet/propresenter7-php-api/issues",
|
||||||
|
"source": "https://github.com/bussnet/propresenter7-php-api"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Thorsten Buss",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.4",
|
"php": "^8.4",
|
||||||
"google/protobuf": "^4.0"
|
"google/protobuf": "^4.0"
|
||||||
|
|
@ -15,5 +40,21 @@
|
||||||
"Rv\\Data\\": "generated/Rv/Data/",
|
"Rv\\Data\\": "generated/Rv/Data/",
|
||||||
"GPBMetadata\\": "generated/GPBMetadata/"
|
"GPBMetadata\\": "generated/GPBMetadata/"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"ProPresenter\\Parser\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/parse-song.php",
|
||||||
|
"bin/parse-playlist.php"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "phpunit",
|
||||||
|
"test:coverage": "phpunit --coverage-text"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"sort-packages": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
composer.lock
generated
2
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "b110e80f59c12eeb362683937b239e85",
|
"content-hash": "b394c8640857fda9e30e27c0910b9a2b",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "google/protobuf",
|
"name": "google/protobuf",
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
# Documentation Guidelines
|
# Documentation Guidelines
|
||||||
|
|
||||||
> How to maintain and extend the `doc/` directory for future AI agents and developers.
|
> How to maintain and extend the `doc/` directory.
|
||||||
|
>
|
||||||
|
> These rules keep the documentation easy to skim for both humans and AI assistants. For general project contribution rules (issues, PRs, tests), see the top-level [README](../README.md#contributing).
|
||||||
|
|
||||||
## Principles
|
## Principles
|
||||||
|
|
||||||
1. **Load only what you need.** Each doc is self-contained for its topic. No doc should require reading other docs to be useful.
|
1. **Self-contained docs.** Each file should be useful on its own. Cross-link generously, but don't force readers to load three other files just to understand one.
|
||||||
2. **One topic per file.** Don't merge unrelated topics. Create a new file instead.
|
2. **One topic per file.** Don't merge unrelated topics — create a new file instead.
|
||||||
3. **Keyword-searchable.** Every new doc must be added to `keywords.md`.
|
3. **Keyword-searchable.** Every new doc must be added to [keywords.md](keywords.md).
|
||||||
4. **Code examples over prose.** Show the API call, not a paragraph explaining it.
|
4. **Code examples over prose.** Show the API call, not a paragraph explaining it.
|
||||||
5. **Keep it current.** When you change code, update the corresponding doc.
|
5. **Keep it current.** When you change code, update the corresponding doc in the same PR.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -154,21 +156,21 @@ When modifying the codebase:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## AI Agent Instructions
|
## Tips for AI Assistants
|
||||||
|
|
||||||
When AGENTS.md tells you to load docs, follow these steps:
|
The docs are also designed to be easy for AI coding assistants to navigate. The conventions matter:
|
||||||
|
|
||||||
1. Read `doc/INDEX.md` to understand what's available
|
1. Read [INDEX.md](INDEX.md) first to understand what's available.
|
||||||
2. Identify which docs match your task (use `keywords.md` if unsure)
|
2. Identify which docs match your task — [keywords.md](keywords.md) maps topics to files.
|
||||||
3. Load ONLY the relevant docs
|
3. Load **only** the relevant docs; the codebase is large.
|
||||||
4. Do NOT load everything -- context window is precious
|
4. The `Quick Reference` section at the top of every API doc is the highest-signal starting point.
|
||||||
|
|
||||||
### Loading patterns
|
### Loading patterns
|
||||||
|
|
||||||
```
|
| Task | Load |
|
||||||
Task: "Parse a song" → Load: doc/api/song.md
|
|------|------|
|
||||||
Task: "Fix protobuf parsing" → Load: doc/formats/pp_song_spec.md
|
| Parse a song | [api/song.md](api/song.md) |
|
||||||
Task: "Create a playlist" → Load: doc/api/playlist.md
|
| Fix protobuf parsing | [formats/pp_song_spec.md](formats/pp_song_spec.md) |
|
||||||
Task: "Debug ZIP issues" → Load: doc/formats/pp_playlist_spec.md + doc/internal/issues.md
|
| Create a playlist | [api/playlist.md](api/playlist.md) |
|
||||||
Task: "Add new feature" → Load: relevant api/ doc + doc/CONTRIBUTING.md
|
| Debug ZIP issues | [formats/pp_playlist_spec.md](formats/pp_playlist_spec.md) + [internal/issues.md](internal/issues.md) |
|
||||||
```
|
| Add a new feature | The relevant `api/*.md` + this file |
|
||||||
|
|
|
||||||
131
doc/INDEX.md
131
doc/INDEX.md
|
|
@ -1,6 +1,8 @@
|
||||||
# ProPresenter Parser Documentation
|
# ProPresenter 7 PHP API — Documentation
|
||||||
|
|
||||||
> **For AI Agents**: Load only the documents you need. Use the keyword index to find relevant sections.
|
> Comprehensive reference for the [ProPresenter 7 PHP API](../README.md) library.
|
||||||
|
>
|
||||||
|
> Each document is self-contained — open the one that matches your task. If you don't know which to load, search [keywords.md](keywords.md) or scan the table below.
|
||||||
|
|
||||||
## Quick Navigation
|
## Quick Navigation
|
||||||
|
|
||||||
|
|
@ -111,119 +113,44 @@ doc/
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## When to Load What
|
## What to Read for Each Task
|
||||||
|
|
||||||
### Task: "Parse a song file"
|
| Task | Read |
|
||||||
```
|
|------|------|
|
||||||
Load: doc/api/song.md
|
| Parse a song file | [api/song.md](api/song.md) |
|
||||||
```
|
| Generate a new playlist | [api/playlist.md](api/playlist.md) |
|
||||||
|
| Read or write a `.probundle` | [api/bundle.md](api/bundle.md) |
|
||||||
### Task: "Generate a new playlist"
|
| Edit a global library file (Macros, Labels, Groups, …) | [api/<library>.md](api/) |
|
||||||
```
|
| Round-trip a theme folder with assets | [api/theme.md](api/theme.md) + [api/bundle.md](api/bundle.md) |
|
||||||
Load: doc/api/playlist.md
|
| Debug protobuf parsing issues | [formats/pp_song_spec.md](formats/pp_song_spec.md) §2–5 |
|
||||||
```
|
| Understand translation handling | [api/song.md](api/song.md) (Translations) + [formats/pp_song_spec.md](formats/pp_song_spec.md) §7 |
|
||||||
|
| Fix ZIP64 issues | [formats/pp_playlist_spec.md](formats/pp_playlist_spec.md) §4 + [formats/pp_bundle_spec.md](formats/pp_bundle_spec.md) §4 |
|
||||||
### Task: "Read/write a .probundle"
|
| Check internal notes / known bugs | [internal/issues.md](internal/issues.md), [internal/learnings.md](internal/learnings.md) |
|
||||||
```
|
|
||||||
Load: doc/api/bundle.md
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task: "Edit a global library file (Macros, Labels, Groups, etc.)"
|
|
||||||
```
|
|
||||||
Load: doc/api/<library>.md
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task: "Round-trip a Theme folder with assets"
|
|
||||||
```
|
|
||||||
Load: doc/api/theme.md
|
|
||||||
Load: doc/api/bundle.md (for the bundle pattern reference)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task: "Debug protobuf parsing issues"
|
|
||||||
```
|
|
||||||
Load: doc/formats/pp_song_spec.md (sections 2-5)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task: "Understand translation handling"
|
|
||||||
```
|
|
||||||
Load: doc/api/song.md (section: Translations)
|
|
||||||
Load: doc/formats/pp_song_spec.md (section 7: Translations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task: "Fix ZIP64 issues"
|
|
||||||
```
|
|
||||||
Load: doc/formats/pp_playlist_spec.md (section 4: ZIP64 Container Format)
|
|
||||||
Load: doc/formats/pp_bundle_spec.md (section 4: ZIP64 EOCD Quirk)
|
|
||||||
Load: doc/internal/learnings.md (search: Zip64Fixer)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
This project provides PHP tools to parse, modify, and generate ProPresenter 7 files:
|
For installation, getting started, and a high-level feature tour see the top-level [README](../README.md).
|
||||||
|
|
||||||
- **Songs** (`.pro`) — Presentation files containing lyrics with groups, slides, arrangements, and translations
|
In short, this library covers:
|
||||||
- **Playlists** (`.proplaylist`) — ZIP archives containing playlist metadata and embedded song files
|
|
||||||
- **Bundles** (`.probundle`) — ZIP archives containing a single presentation with embedded media assets
|
- **Songs** (`.pro`) — protobuf files with lyrics, groups, slides, arrangements, translations
|
||||||
|
- **Playlists** (`.proplaylist`) — ZIP64 archives with embedded songs and media
|
||||||
|
- **Bundles** (`.probundle`) — ZIP archives bundling a single song with its media assets
|
||||||
|
- **Themes** — folder with a `Theme` protobuf and an `Assets/` directory
|
||||||
- **Global library files** — `Macros`, `Labels`, `Groups`, `ClearGroups`, `CCLI`, `Messages`, `Timers`, `Stage`, `Workspace`, `Props`, `TestPatterns`, `Calendar`, `KeyMappings`, `CommunicationDevices` (JSON)
|
- **Global library files** — `Macros`, `Labels`, `Groups`, `ClearGroups`, `CCLI`, `Messages`, `Timers`, `Stage`, `Workspace`, `Props`, `TestPatterns`, `Calendar`, `KeyMappings`, `CommunicationDevices` (JSON)
|
||||||
- **Theme folders** — directory with a `Theme` protobuf file plus an `Assets/` subdirectory of media
|
|
||||||
|
|
||||||
### Key Components
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `src/Song.php` | Song wrapper (read/modify `.pro` files) |
|
|
||||||
| `src/ProFileReader.php` | Read `.pro` files |
|
|
||||||
| `src/ProFileWriter.php` | Write `.pro` files |
|
|
||||||
| `src/ProFileGenerator.php` | Generate `.pro` files from scratch |
|
|
||||||
| `src/PlaylistArchive.php` | Playlist wrapper (read/modify `.proplaylist` files) |
|
|
||||||
| `src/ProPlaylistReader.php` | Read `.proplaylist` files |
|
|
||||||
| `src/ProPlaylistWriter.php` | Write `.proplaylist` files |
|
|
||||||
| `src/ProPlaylistGenerator.php` | Generate `.proplaylist` files from scratch |
|
|
||||||
| `src/PresentationBundle.php` | Bundle wrapper (read/write `.probundle` files) |
|
|
||||||
| `src/ProBundleReader.php` | Read `.probundle` files |
|
|
||||||
| `src/ProBundleWriter.php` | Write `.probundle` files |
|
|
||||||
| `src/ThemeBundle.php` | Theme folder wrapper (Template.Document + Assets/) |
|
|
||||||
| `src/ThemeFileReader.php` / `ThemeFileWriter.php` | Read/write theme folders |
|
|
||||||
| `src/MacroLibrary.php` / `MacrosFileReader.php` / `MacrosFileWriter.php` | Macros file IO |
|
|
||||||
| `src/LabelLibrary.php` / `LabelsFileReader.php` / `LabelsFileWriter.php` | Labels file IO |
|
|
||||||
| `src/GroupLibrary.php` / `GroupsFileReader.php` / `GroupsFileWriter.php` | Groups file IO |
|
|
||||||
| `src/ClearGroupsLibrary.php` / `ClearGroupsFileReader.php` / `ClearGroupsFileWriter.php` | ClearGroups file IO |
|
|
||||||
| `src/CCLILibrary.php` / `CCLIFileReader.php` / `CCLIFileWriter.php` | CCLI file IO |
|
|
||||||
| `src/MessageLibrary.php` / `MessagesFileReader.php` / `MessagesFileWriter.php` | Messages file IO |
|
|
||||||
| `src/TimersLibrary.php` / `TimersFileReader.php` / `TimersFileWriter.php` | Timers file IO |
|
|
||||||
| `src/StageLibrary.php` / `StageFileReader.php` / `StageFileWriter.php` | Stage file IO |
|
|
||||||
| `src/WorkspaceLibrary.php` / `WorkspaceFileReader.php` / `WorkspaceFileWriter.php` | Workspace file IO |
|
|
||||||
| `src/PropLibrary.php` / `PropsFileReader.php` / `PropsFileWriter.php` | Props file IO |
|
|
||||||
| `src/TestPatternsLibrary.php` / `TestPatternsFileReader.php` / `TestPatternsFileWriter.php` | TestPatterns file IO |
|
|
||||||
| `src/CalendarLibrary.php` / `CalendarFileReader.php` / `CalendarFileWriter.php` | Calendar file IO |
|
|
||||||
| `src/KeyMappingsLibrary.php` / `KeyMappingsFileReader.php` / `KeyMappingsFileWriter.php` | KeyMappings file IO |
|
|
||||||
| `src/CommunicationDevicesLibrary.php` / `CommunicationDevicesFileReader.php` / `CommunicationDevicesFileWriter.php` | CommunicationDevices JSON file IO |
|
|
||||||
|
|
||||||
### CLI Tools
|
### CLI Tools
|
||||||
|
|
||||||
|
Every supported file type ships with an inspector script in [`bin/`](../bin/). Examples:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Songs / playlists / bundles
|
|
||||||
php bin/parse-song.php path/to/song.pro
|
php bin/parse-song.php path/to/song.pro
|
||||||
php bin/parse-playlist.php path/to/playlist.proplaylist
|
php bin/parse-playlist.php path/to/playlist.proplaylist
|
||||||
|
|
||||||
# Global library files
|
|
||||||
php bin/parse-macros.php path/to/Macros
|
|
||||||
php bin/parse-labels.php path/to/Labels
|
|
||||||
php bin/parse-groups.php path/to/Groups
|
|
||||||
php bin/parse-clear-groups.php path/to/ClearGroups
|
|
||||||
php bin/parse-ccli.php path/to/CCLI
|
|
||||||
php bin/parse-messages.php path/to/Messages
|
|
||||||
php bin/parse-timers.php path/to/Timers
|
|
||||||
php bin/parse-stage.php path/to/Stage
|
|
||||||
php bin/parse-workspace.php path/to/Workspace
|
|
||||||
php bin/parse-props.php path/to/Props
|
|
||||||
php bin/parse-test-patterns.php path/to/TestPatterns
|
|
||||||
php bin/parse-calendar.php path/to/Calendar
|
|
||||||
php bin/parse-key-mappings.php path/to/KeyMappings
|
|
||||||
php bin/parse-communication-devices.php path/to/CommunicationDevices
|
|
||||||
|
|
||||||
# Theme folder
|
|
||||||
php bin/parse-theme.php path/to/ThemeFolder
|
php bin/parse-theme.php path/to/ThemeFolder
|
||||||
|
php bin/parse-macros.php path/to/Macros
|
||||||
|
# … and one for every other global library file
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See the [README](../README.md#cli-tools) for the full list.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Keyword Index
|
# Keyword Index
|
||||||
|
|
||||||
> Search this file to find which documents to load for specific topics.
|
> Search this file (Ctrl+F / Cmd+F) to jump to the right document for a topic.
|
||||||
|
|
||||||
## File Formats
|
## File Formats
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue