Initial commit — Rosary Presenter App

Full source for loveandrosary.com: slide-based Rosary/novena/Divine Mercy
Chaplet presentation tool with multi-user roles, SVG bead ring, audio uploads,
donate strip, and public session profiles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 18:44:08 -07:00
commit 663fde3909
46 changed files with 10902 additions and 0 deletions
+261
View File
@@ -0,0 +1,261 @@
<?php
/**
* includes/build_slides.php
*
* build_slides(array $session): array
*
* Assembles the full slide sequence for a rosary session.
* Applies variable substitution for {name}, {pronoun}, {pronoun_obj}, {pronoun_poss}.
*/
require_once __DIR__ . '/../data/prayers.php';
/**
* Returns the slide array for one decade of the Chaplet of Divine Mercy.
*
* Large bead : "Eternal Father…"
* Small beads: "For the sake of His sorrowful Passion…" × 10
* No mystery announcement; no Glory Be between decades.
*
* @param int $decade_num 15
* @param int $of_bead_index bead_index for the large (Our Father) bead
* @param int $hm_bead_start bead_index for the first small bead of this decade
*/
function build_chaplet_decade_slides(int $decade_num, int $of_bead_index, int $hm_bead_start): array {
$slides = [];
$slides[] = [
'id' => 'dm_eternal_father_d' . $decade_num,
'type' => 'prayer',
'section' => 'dm_chaplet_decade_' . $decade_num,
'title' => 'Eternal Father',
'leader' => "Eternal Father, I offer You the Body and Blood,\nSoul and Divinity of Your dearly beloved Son,\nOur Lord Jesus Christ,",
'all' => "in atonement for our sins and those of the whole world.",
'bead' => 'large',
'bead_index' => $of_bead_index,
];
for ($i = 0; $i < 10; $i++) {
$slides[] = [
'id' => 'dm_for_sake_d' . $decade_num . '_' . ($i + 1),
'type' => 'prayer',
'section' => 'dm_chaplet_decade_' . $decade_num,
'title' => 'For the Sake of His Sorrowful Passion',
'leader' => 'For the sake of His sorrowful Passion,',
'all' => 'have mercy on us and on the whole world.',
'bead' => 'small',
'bead_index' => $hm_bead_start + $i,
];
}
return $slides;
}
/**
* Build the complete slide array for a session.
*
* @param array $session Row from the sessions table (keys match column names)
* @return array Flat array of slide arrays
*/
function build_slides(array $session): array {
global $opening, $mysteries, $hail_holy_queen, $rosary_closing_prayer,
$litany_passion, $novena_prayers, $litany_departed, $closing,
$divine_mercy_opening, $divine_mercy_novena_prayers,
$divine_mercy_chaplet_opening, $divine_mercy_chaplet_close;
$slides = [];
// -----------------------------------------------------------------------
// 1. Cover slide
// -----------------------------------------------------------------------
$cover_title = '';
$cover_all = '';
switch ($session['occasion']) {
case 'novena_deceased':
$day = (int)($session['novena_day'] ?? 1);
$cover_title = 'Nine-Day Novena Rosary';
$cover_all = "In Loving Memory of\n{name}\n{subject_dates}\n\nDay {$day} of 9";
break;
case 'memorial':
$cover_title = 'Memorial Rosary';
$cover_all = "In Loving Memory of\n{name}\n{subject_dates}";
break;
case 'divine_mercy_novena':
$day = (int)($session['novena_day'] ?? 1);
$cover_title = 'Divine Mercy Novena';
$cover_all = "Chaplet of Divine Mercy\n\nDay {$day} of 9";
break;
case 'general_rosary':
default:
$cover_title = 'The Holy Rosary';
$cover_all = ucfirst($session['mystery_set']) . ' Mysteries';
break;
}
$slides[] = [
'id' => 'cover',
'type' => 'cover',
'section' => 'cover',
'title' => $cover_title,
'leader' => '',
'all' => $cover_all,
'bead' => null,
'bead_index' => null,
'photo_path' => $session['photo_path'] ?? null,
];
// -----------------------------------------------------------------------
// 2. Opening prayers
// -----------------------------------------------------------------------
if ($session['occasion'] === 'divine_mercy_novena') {
// Pre-chaplet devotion: opening prayer + O Blood and Water × 3
foreach ($divine_mercy_opening as $slide) {
$slides[] = $slide;
}
// Day-specific intention and prayer
$day = (int)($session['novena_day'] ?? 1);
if (isset($divine_mercy_novena_prayers[$day])) {
foreach ($divine_mercy_novena_prayers[$day] as $slide) {
$slides[] = $slide;
}
}
// Chaplet opening on stem beads (Sign of Cross, Our Father, Hail Mary, Creed)
foreach ($divine_mercy_chaplet_opening as $slide) {
$slides[] = $slide;
}
} else {
foreach ($opening as $slide) {
$slides[] = $slide;
}
}
// -----------------------------------------------------------------------
// 3. Five decades
//
// Bead layout:
// Bead 0: Crucifix (Sign of Cross / Creed)
// Bead 1: large (Our Father, stem)
// Beads 24: small (3 Hail Marys / Creed for chaplet, stem)
// Bead 5: large (Our Father, Decade 1)
// Beads 615: small (Decade 1, 10 HMs / For the sake…)
// Bead 16: large (Our Father, Decade 2)
// Beads 1726: small (Decade 2)
// Bead 27: large (Our Father, Decade 3)
// Beads 2837: small (Decade 3)
// Bead 38: large (Our Father, Decade 4)
// Beads 3948: small (Decade 4)
// Bead 49: large (Our Father, Decade 5)
// Beads 5059: small (Decade 5)
// -----------------------------------------------------------------------
$decade_bead_map = [
// decade => [our_father_index, first_hm_index]
1 => [5, 6],
2 => [16, 17],
3 => [27, 28],
4 => [38, 39],
5 => [49, 50],
];
if ($session['occasion'] === 'divine_mercy_novena') {
for ($d = 1; $d <= 5; $d++) {
[$of_idx, $hm_idx] = $decade_bead_map[$d];
foreach (build_chaplet_decade_slides($d, $of_idx, $hm_idx) as $slide) {
$slides[] = $slide;
}
}
} else {
$mystery_set = $mysteries[$session['mystery_set']] ?? $mysteries['sorrowful'];
for ($d = 1; $d <= 5; $d++) {
[$of_idx, $hm_idx] = $decade_bead_map[$d];
$mystery_slide = $mystery_set[$d - 1];
$decade_slides = build_decade_slides($d, $mystery_slide, $of_idx, $hm_idx);
foreach ($decade_slides as $slide) {
$slides[] = $slide;
}
}
}
// -----------------------------------------------------------------------
// 4. Post-decade prayers by occasion
// -----------------------------------------------------------------------
switch ($session['occasion']) {
case 'novena_deceased':
// Hail Holy Queen
foreach ($hail_holy_queen as $slide) {
$slides[] = $slide;
}
// Day-specific novena prayer
$day = (int)($session['novena_day'] ?? 1);
if (isset($novena_prayers[$day])) {
$slides[] = $novena_prayers[$day];
}
// Litany of the Passion
foreach ($litany_passion as $slide) {
$slides[] = $slide;
}
// Litany for the Departed
foreach ($litany_departed as $slide) {
$slides[] = $slide;
}
break;
case 'divine_mercy_novena':
// Holy God, Holy Mighty One, Holy Immortal One × 3
foreach ($divine_mercy_chaplet_close as $slide) {
$slides[] = $slide;
}
break;
case 'memorial':
case 'general_rosary':
default:
foreach ($hail_holy_queen as $slide) {
$slides[] = $slide;
}
$slides[] = $rosary_closing_prayer;
break;
}
// -----------------------------------------------------------------------
// 5. Closing slide — inject photo for personal occasions
// -----------------------------------------------------------------------
$occasion_key = $session['occasion'];
if (!isset($closing[$occasion_key])) {
$occasion_key = 'general_rosary';
}
$closing_slide = $closing[$occasion_key];
if (in_array($occasion_key, ['novena_deceased', 'memorial'])) {
$closing_slide['photo_path'] = $session['photo_path'] ?? null;
}
$slides[] = $closing_slide;
// -----------------------------------------------------------------------
// 6. Variable substitution
// -----------------------------------------------------------------------
$name = $session['subject_name'] ?? '';
$pronoun = $session['subject_pronoun'] ?? 'he'; // 'he' or 'she'
$dates = $session['subject_dates'] ?? '';
$pronoun_obj = ($pronoun === 'she') ? 'her' : 'him';
$pronoun_poss = ($pronoun === 'she') ? 'her' : 'his';
$pronoun_cap = ucfirst($pronoun);
$find = ['{name}', '{pronoun}', '{pronoun_obj}', '{pronoun_poss}', '{subject_dates}'];
$replace = [$name, $pronoun, $pronoun_obj, $pronoun_poss, $dates];
foreach ($slides as &$slide) {
$slide['title'] = str_replace($find, $replace, $slide['title'] ?? '');
$slide['leader'] = str_replace($find, $replace, $slide['leader'] ?? '');
$slide['all'] = str_replace($find, $replace, $slide['all'] ?? '');
if (isset($slide['subtitle'])) {
$slide['subtitle'] = str_replace($find, $replace, $slide['subtitle']);
}
}
unset($slide);
return $slides;
}