propresenter-php/doc/api/playlist.md
Thorsten Bus 22ba4aff7d refactor: make repo Composer-compatible by moving php/ to root and ref/ to doc/reference_samples
- Move src/, tests/, bin/, generated/, proto/, composer.json, composer.lock, phpunit.xml from php/ to repo root
- Move ref/ to doc/reference_samples/ for better organization
- Remove vendor/ from git tracking (now properly gitignored)
- Update all test file paths (dirname adjustments and ref/ -> doc/reference_samples/)
- Update all documentation paths (AGENTS.md, doc/*.md)
- Remove php.bak/ directory
- All 252 tests pass
2026-03-30 13:26:29 +02:00

5.1 KiB

Playlist Parser API

PHP module for reading, modifying, and generating ProPresenter .proplaylist files.

Quick Reference

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

use ProPresenter\Parser\ProPlaylistReader;

$archive = ProPlaylistReader::read('path/to/playlist.proplaylist');

Metadata Access

$archive->getName();   // Playlist name
$archive->getUuid();   // Playlist UUID
$archive->getNotes();  // Playlist notes

Entries

Entries are playlist items (songs, headers, placeholders).

foreach ($archive->getEntries() as $entry) {
    $entry->getType();   // 'song', 'header', 'placeholder', 'cue'
    $entry->getName();   // Entry display name
    $entry->getUuid();   // Entry UUID
}

Song Entries (Presentations)

if ($entry->getType() === 'presentation') {
    $entry->getDocumentPath();       // "file:///path/to/song.pro"
    $entry->getDocumentFilename();   // "song.pro"
    $entry->getArrangementName();    // "normal"
    $entry->getArrangementUuid();    // "uuid-string"
}

Header Entries

if ($entry->getType() === 'header') {
    $entry->getHeaderColor();  // [r, g, b, a] RGBA floats
}

Embedded Songs

Playlists can contain embedded .pro files. Access them lazily:

if ($entry->isEmbedded()) {
    $song = $archive->getEmbeddedSong($entry);
    $song->getName();
    foreach ($song->getGroups() as $group) {
        echo $group->getName();
    }
}

Embedded Files

// 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

use ProPresenter\Parser\ProPlaylistWriter;

$archive->setName("New Playlist Name");
$archive->setNotes("Updated notes");

ProPlaylistWriter::write($archive, 'output.proplaylist');

Generating Playlists

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

// 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

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

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 Section 4 for details.


Key Files

File Purpose
src/PlaylistArchive.php Top-level playlist wrapper
src/PlaylistEntry.php Entry wrapper (song/header/placeholder)
src/PlaylistNode.php Playlist node wrapper
src/ProPlaylistReader.php Reads .proplaylist files
src/ProPlaylistWriter.php Writes .proplaylist files
src/ProPlaylistGenerator.php Generates .proplaylist files
src/Zip64Fixer.php Fixes ProPresenter ZIP64 header bug
bin/parse-playlist.php CLI tool

See Also