230 lines
5.1 KiB
Markdown
230 lines
5.1 KiB
Markdown
# Playlist Parser API
|
|
|
|
> PHP module for reading, modifying, and generating ProPresenter `.proplaylist` files.
|
|
|
|
## Quick Reference
|
|
|
|
```php
|
|
use ProPresenter\Parser\ProPlaylistReader;
|
|
use ProPresenter\Parser\ProPlaylistWriter;
|
|
use ProPresenter\Parser\ProPlaylistGenerator;
|
|
|
|
// Read
|
|
$archive = ProPlaylistReader::read('path/to/playlist.proplaylist');
|
|
|
|
// Modify
|
|
$archive->setName("New Playlist Name");
|
|
ProPlaylistWriter::write($archive, 'output.proplaylist');
|
|
|
|
// Generate
|
|
$archive = ProPlaylistGenerator::generate('Playlist Name', $entries, $metadata);
|
|
```
|
|
|
|
---
|
|
|
|
## Reading Playlists
|
|
|
|
```php
|
|
use ProPresenter\Parser\ProPlaylistReader;
|
|
|
|
$archive = ProPlaylistReader::read('path/to/playlist.proplaylist');
|
|
```
|
|
|
|
### Metadata Access
|
|
|
|
```php
|
|
$archive->getName(); // Playlist name
|
|
$archive->getUuid(); // Playlist UUID
|
|
$archive->getNotes(); // Playlist notes
|
|
```
|
|
|
|
---
|
|
|
|
## Entries
|
|
|
|
Entries are playlist items (songs, headers, placeholders).
|
|
|
|
```php
|
|
foreach ($archive->getEntries() as $entry) {
|
|
$entry->getType(); // 'song', 'header', 'placeholder', 'cue'
|
|
$entry->getName(); // Entry display name
|
|
$entry->getUuid(); // Entry UUID
|
|
}
|
|
```
|
|
|
|
### Song Entries (Presentations)
|
|
|
|
```php
|
|
if ($entry->getType() === 'presentation') {
|
|
$entry->getDocumentPath(); // "file:///path/to/song.pro"
|
|
$entry->getDocumentFilename(); // "song.pro"
|
|
$entry->getArrangementName(); // "normal"
|
|
$entry->getArrangementUuid(); // "uuid-string"
|
|
}
|
|
```
|
|
|
|
### Header Entries
|
|
|
|
```php
|
|
if ($entry->getType() === 'header') {
|
|
$entry->getHeaderColor(); // [r, g, b, a] RGBA floats
|
|
}
|
|
```
|
|
|
|
### Embedded Songs
|
|
|
|
Playlists can contain embedded `.pro` files. Access them lazily:
|
|
|
|
```php
|
|
if ($entry->isEmbedded()) {
|
|
$song = $archive->getEmbeddedSong($entry);
|
|
$song->getName();
|
|
foreach ($song->getGroups() as $group) {
|
|
echo $group->getName();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Embedded Files
|
|
|
|
```php
|
|
// List embedded .pro files
|
|
$proFiles = $archive->getEmbeddedProFiles();
|
|
// ['Song1.pro' => $bytes, 'Song2.pro' => $bytes]
|
|
|
|
// List embedded media files
|
|
$mediaFiles = $archive->getEmbeddedMediaFiles();
|
|
// ['Users/me/Pictures/slide.jpg' => $bytes]
|
|
|
|
// Get specific embedded song
|
|
$song = $archive->getEmbeddedSong($entry);
|
|
```
|
|
|
|
---
|
|
|
|
## Modifying Playlists
|
|
|
|
```php
|
|
use ProPresenter\Parser\ProPlaylistWriter;
|
|
|
|
$archive->setName("New Playlist Name");
|
|
$archive->setNotes("Updated notes");
|
|
|
|
ProPlaylistWriter::write($archive, 'output.proplaylist');
|
|
```
|
|
|
|
---
|
|
|
|
## Generating Playlists
|
|
|
|
```php
|
|
use ProPresenter\Parser\ProPlaylistGenerator;
|
|
|
|
$archive = ProPlaylistGenerator::generate(
|
|
'Sunday Service',
|
|
[
|
|
[
|
|
'type' => 'header',
|
|
'name' => 'Worship',
|
|
'color' => [0.95, 0.27, 0.27, 1.0],
|
|
],
|
|
[
|
|
'type' => 'presentation',
|
|
'name' => 'Amazing Grace',
|
|
'path' => 'file:///path/to/amazing-grace.pro',
|
|
'arrangement' => 'normal',
|
|
],
|
|
[
|
|
'type' => 'presentation',
|
|
'name' => 'Oceans',
|
|
'path' => 'file:///path/to/oceans.pro',
|
|
'arrangement' => 'verse-only',
|
|
],
|
|
[
|
|
'type' => 'placeholder',
|
|
'name' => 'TBD',
|
|
],
|
|
],
|
|
['notes' => 'Sunday morning service']
|
|
);
|
|
|
|
// Generate and write in one call
|
|
ProPlaylistGenerator::generateAndWrite(
|
|
'output.proplaylist',
|
|
'Playlist Name',
|
|
$entries,
|
|
$metadata
|
|
);
|
|
```
|
|
|
|
### Entry Types
|
|
|
|
```php
|
|
// Header (section divider)
|
|
['type' => 'header', 'name' => 'Section Name', 'color' => [r, g, b, a]]
|
|
|
|
// Presentation (song reference)
|
|
['type' => 'presentation', 'name' => 'Song Name', 'path' => 'file:///...', 'arrangement' => 'name']
|
|
|
|
// Placeholder (empty slot)
|
|
['type' => 'placeholder', 'name' => 'TBD']
|
|
```
|
|
|
|
---
|
|
|
|
## CLI Tool
|
|
|
|
```bash
|
|
php php/bin/parse-playlist.php path/to/playlist.proplaylist
|
|
```
|
|
|
|
Output includes:
|
|
- Playlist metadata (name, UUID, notes)
|
|
- Entries with type-specific details
|
|
- Embedded file counts
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
```php
|
|
try {
|
|
$archive = ProPlaylistReader::read('playlist.proplaylist');
|
|
} catch (\RuntimeException $e) {
|
|
// File not found, empty file, invalid ZIP, or invalid protobuf
|
|
echo "Error: " . $e->getMessage();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ZIP64 Notes
|
|
|
|
ProPresenter exports playlists with a broken ZIP64 header (98-byte offset discrepancy). The reader automatically fixes this before parsing. The writer produces clean standard ZIPs without the bug.
|
|
|
|
See [Format Specification](../formats/pp_playlist_spec.md) Section 4 for details.
|
|
|
|
---
|
|
|
|
## Key Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `php/src/PlaylistArchive.php` | Top-level playlist wrapper |
|
|
| `php/src/PlaylistEntry.php` | Entry wrapper (song/header/placeholder) |
|
|
| `php/src/PlaylistNode.php` | Playlist node wrapper |
|
|
| `php/src/ProPlaylistReader.php` | Reads `.proplaylist` files |
|
|
| `php/src/ProPlaylistWriter.php` | Writes `.proplaylist` files |
|
|
| `php/src/ProPlaylistGenerator.php` | Generates `.proplaylist` files |
|
|
| `php/src/Zip64Fixer.php` | Fixes ProPresenter ZIP64 header bug |
|
|
| `php/bin/parse-playlist.php` | CLI tool |
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [Format Specification](../formats/pp_playlist_spec.md) — Binary format details
|
|
- [Song API](song.md) — `.pro` file handling
|