No description
  • Python 90.4%
  • JavaScript 4%
  • CSS 3.7%
  • HTML 1%
  • Dockerfile 0.9%
Find a file
Paul Burton be5e756b1b Stamp generated files as macOS-authored (platform=MACOS)
Flip every platform flag from WINDOWS/WIN32 to MACOS so the file is
internally consistent with a real Mac-authored .pro/.proPlaylist, which
the macOS renderer treats as native:
- ApplicationInfo.platform 2->1, with platform_version bumped 10->13
  (macOS Ventura) so it doesn't read as "macOS 10"
- media URL platform (_pb_media_url) 2->1
- playlist item document_path URL platform 2->1

Values match real PP-authored files. Cross-platform import on Windows is
handled by the playlist's uses_relative_urls flag (real platform=1 files
open fine on Windows); to be verified on the Windows machine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 17:14:18 +01:00
data Handle Sunday School items; generalise video-led item handling 2026-06-13 14:02:54 +01:00
docs Add comprehensive .proPlaylist/.pro format reference documentation 2026-06-07 23:29:02 +01:00
src Stamp generated files as macOS-authored (platform=MACOS) 2026-06-17 17:14:18 +01:00
static Handle Sunday School items; generalise video-led item handling 2026-06-13 14:02:54 +01:00
templates Show download spinner near the button, not the top-level plan spinner 2026-06-12 12:41:52 +01:00
tools Add lyrics post-processing: British spellings, repeat removal, slide splitting 2026-06-08 22:14:07 +01:00
.containerignore Add working Containerfile and .containerignore 2026-06-09 18:06:18 +01:00
.gitignore Switch CCLI login to undetected-chromedriver; add Chrome to container 2026-06-07 20:34:57 +01:00
app.py Handle Sunday School items; generalise video-led item handling 2026-06-13 14:02:54 +01:00
Containerfile Generate Bible text slides for Reading plan items 2026-06-12 22:10:18 +01:00
Dockerfile Symlink Dockerfile 2026-06-09 18:39:50 +01:00
README.md Switch CCLI login to undetected-chromedriver; add Chrome to container 2026-06-07 20:34:57 +01:00
requirements.txt Switch from Flask dev server to gunicorn 2026-06-12 13:25:31 +01:00

cspp — ChurchSuite → ProPresenter Playlist Generator

Generates a ProPresenter 7 .proPlaylist file from a ChurchSuite service plan URL.

What it does

  1. Loads a ChurchSuite plan URL (handles Cloudflare protection via a real browser)
  2. Identifies songs vs. other items (prayer, reading, sermon, communion, …)
  3. Fetches lyrics where possible (see Lyric Sources)
  4. Builds a .proPlaylist zip archive:
    • Each song → a .pro presentation with slides grouped as Intro / Verse / Chorus / Bridge / … / Outro
    • Each non-song → a ProPresenter placeholder item (titled appropriately)
  5. Delivers the file as a browser download

Running locally

python app.py
# open http://localhost:5000

Dependencies (Python 3.12+):

pip install -r requirements.txt
playwright install chromium

Running in a container

# Build
docker build -f Containerfile -t cspp .
# or
podman build -f Containerfile -t cspp .

# Run
docker run -p 5000:5000 cspp
# open http://localhost:5000

The official Playwright image is used as the base, so no extra browser setup is needed.

CCLI SongSelect lyrics (optional)

Two auth strategies are supported, tried in order:

Option A — Cookie file (recommended, works everywhere)

The SongSelect login page is protected by Cloudflare Turnstile which blocks automated browsers. The reliable workaround is to export your cookies from a real browser session:

  1. Log into https://songselect.ccli.com/ in Chrome or Edge.
  2. Install the Cookie-Editor extension (by Fanboy).
  3. Click the extension icon → ExportExport as JSON → save the file.
  4. Pass the path to the container:
docker run -p 5000:5000 \
  -v /path/to/ccli_cookies.json:/cookies.json:ro \
  -e CCLI_COOKIES_FILE=/cookies.json \
  cspp

Cookies typically stay valid for 30 days (longer with "Keep me signed in"). Re-export when lyrics stop being fetched.

Option B — Username / password

Uses undetected-chromedriver, which patches the ChromeDriver binary so Cloudflare Turnstile passes automatically (typically within 3 seconds). Requires Google Chrome to be installed on the system.

CCLI_USERNAME=you@example.com CCLI_PASSWORD=yourpassword python app.py

Or in Docker/Podman (Chrome is installed in the container image):

docker run -p 5000:5000 \
  -e CCLI_USERNAME=you@example.com \
  -e CCLI_PASSWORD=yourpassword \
  cspp

Without either option, songs will get blank placeholder presentations.

Project structure

app.py                        Flask entry point (routes: /, /preview, /generate)
src/
  churchsuite.py              Playwright-based plan scraper
  ccli.py                     CCLI SongSelect lyric fetcher (UCD login or cookie injection)
  lyrics.py                   Lyric fetching pipeline (manual → CCLI → plan HTML)
  propresenter/
    proto_utils.py            Low-level protobuf binary encoding
    presentation.py           .pro file builder (slides, groups, RTF text)
    playlist.py               .proPlaylist ZIP assembler
templates/index.html          Web UI
static/{style.css,app.js}
Containerfile

Lyric sources

Tried in order:

  1. CCLI SongSelect requires auth config (see above); fetches all songs in one browser session
  2. ChurchSuite plan HTML lyrics sometimes embedded in the rendered plan page

Songs with no lyrics get a minimal blank presentation (Intro + blank slide + Outro). The operator can link to an existing library file in ProPresenter if needed.

Playlist format notes

.proPlaylist is a ZIP archive containing:

File Description
data Protobuf-encoded playlist (undocumented wrapper + rv.data.Playlist)
SongName.pro Protobuf-encoded rv.data.Presentation for each song

The proto schemas are from ProPresenter7-Proto.

Planned / future work

  • Background images expose a set of stock images; let user pick one per song or globally
  • Reading slides replace the "Reading" placeholder with slides showing the Bible text
  • Prayer slides simple "Prayer" display slide
  • ProPresenter library matching detect songs already in the library and reference them by path instead of bundling a new .pro file
  • More lyric sources OpenSong library, Planning Center songs API