5a45320057
One folder per song under songs/. Tracks PPTX slide files and Python generation scripts. PDFs and videos excluded (too large for git; originals are in Google Drive). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
151 lines
4.1 KiB
Python
151 lines
4.1 KiB
Python
from pptx import Presentation
|
|
from pptx.util import Inches, Pt
|
|
from pptx.dml.color import RGBColor
|
|
from pptx.enum.text import PP_ALIGN
|
|
from pptx.oxml.ns import qn
|
|
from lxml import etree
|
|
|
|
OUT_PATH = r"C:\Users\jhodgkin\Documents\dev\primary-song-slides\MyCountryTisOfThee.pptx"
|
|
|
|
SLIDE_W = Inches(13.333)
|
|
SLIDE_H = Inches(7.5)
|
|
|
|
NAVY = RGBColor(0x0D, 0x27, 0x6D)
|
|
GOLD = RGBColor(0xF5, 0xC5, 0x18)
|
|
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
|
|
|
|
VERSES = [
|
|
(
|
|
"Verse 1",
|
|
"My country, 'tis of thee,\n"
|
|
"Sweet land of liberty,\n"
|
|
"Of thee I sing;\n"
|
|
"Land where my fathers died,\n"
|
|
"Land of the pilgrims' pride,\n"
|
|
"From ev'ry mountainside\n"
|
|
"Let freedom ring!"
|
|
),
|
|
(
|
|
"Verse 4",
|
|
"Our fathers' God, to thee,\n"
|
|
"Author of liberty,\n"
|
|
"To thee we sing;\n"
|
|
"Long may our land be bright\n"
|
|
"With freedom's holy light.\n"
|
|
"Protect us by thy might,\n"
|
|
"Great God, our King!"
|
|
),
|
|
]
|
|
|
|
|
|
def set_background_color(slide, color):
|
|
"""Fill slide background with a solid color."""
|
|
bg = slide.background
|
|
fill = bg.fill
|
|
fill.solid()
|
|
fill.fore_color.rgb = color
|
|
|
|
|
|
def add_text_paragraph(tf, text, font_size, color, bold=False, space_before=0):
|
|
p = tf.add_paragraph()
|
|
p.alignment = PP_ALIGN.CENTER
|
|
if space_before:
|
|
pPr = p._pPr
|
|
if pPr is None:
|
|
pPr = p._p.get_or_add_pPr()
|
|
pPr.set(qn("a:spcBef"), None)
|
|
spcBef = etree.SubElement(pPr, qn("a:spcBef"))
|
|
spcPts = etree.SubElement(spcBef, qn("a:spcPts"))
|
|
spcPts.set("val", str(space_before * 100))
|
|
run = p.add_run()
|
|
run.text = text
|
|
run.font.size = font_size
|
|
run.font.color.rgb = color
|
|
run.font.bold = bold
|
|
return p
|
|
|
|
|
|
def add_slide(prs, blank_layout, verse_label, verse_text):
|
|
slide = prs.slides.add_slide(blank_layout)
|
|
set_background_color(slide, NAVY)
|
|
|
|
# Gold decorative rule above title
|
|
rule_top = Inches(0.55)
|
|
rule_h = Inches(0.06)
|
|
rule = slide.shapes.add_shape(
|
|
1, # MSO_SHAPE_TYPE.RECTANGLE
|
|
Inches(1.5), rule_top, SLIDE_W - Inches(3.0), rule_h
|
|
)
|
|
rule.fill.solid()
|
|
rule.fill.fore_color.rgb = GOLD
|
|
rule.line.fill.background()
|
|
|
|
# Song title
|
|
title_box = slide.shapes.add_textbox(Inches(0.5), Inches(0.65), SLIDE_W - Inches(1.0), Inches(0.85))
|
|
tf = title_box.text_frame
|
|
tf.word_wrap = False
|
|
p = tf.paragraphs[0]
|
|
p.alignment = PP_ALIGN.CENTER
|
|
run = p.add_run()
|
|
run.text = "My Country, 'Tis of Thee"
|
|
run.font.size = Pt(36)
|
|
run.font.color.rgb = GOLD
|
|
run.font.bold = True
|
|
|
|
# Verse label
|
|
label_box = slide.shapes.add_textbox(Inches(0.5), Inches(1.45), SLIDE_W - Inches(1.0), Inches(0.5))
|
|
tf2 = label_box.text_frame
|
|
p2 = tf2.paragraphs[0]
|
|
p2.alignment = PP_ALIGN.CENTER
|
|
run2 = p2.add_run()
|
|
run2.text = verse_label
|
|
run2.font.size = Pt(22)
|
|
run2.font.color.rgb = WHITE
|
|
run2.font.bold = False
|
|
run2.font.italic = True
|
|
|
|
# Gold rule below label
|
|
rule2 = slide.shapes.add_shape(
|
|
1,
|
|
Inches(1.5), Inches(1.95), SLIDE_W - Inches(3.0), rule_h
|
|
)
|
|
rule2.fill.solid()
|
|
rule2.fill.fore_color.rgb = GOLD
|
|
rule2.line.fill.background()
|
|
|
|
# Verse lyrics
|
|
lyric_box = slide.shapes.add_textbox(Inches(0.5), Inches(2.1), SLIDE_W - Inches(1.0), Inches(5.0))
|
|
tf3 = lyric_box.text_frame
|
|
tf3.word_wrap = True
|
|
lines = verse_text.split("\n")
|
|
for i, line in enumerate(lines):
|
|
if i == 0:
|
|
p = tf3.paragraphs[0]
|
|
else:
|
|
p = tf3.add_paragraph()
|
|
p.alignment = PP_ALIGN.CENTER
|
|
run = p.add_run()
|
|
run.text = line
|
|
run.font.size = Pt(40)
|
|
run.font.color.rgb = WHITE
|
|
run.font.bold = False
|
|
|
|
print(f" Added: {verse_label}")
|
|
|
|
|
|
def main():
|
|
prs = Presentation()
|
|
prs.slide_width = SLIDE_W
|
|
prs.slide_height = SLIDE_H
|
|
blank_layout = prs.slide_layouts[6]
|
|
|
|
for label, text in VERSES:
|
|
add_slide(prs, blank_layout, label, text)
|
|
|
|
prs.save(OUT_PATH)
|
|
print(f"\nSaved: {OUT_PATH} ({len(VERSES)} slides)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|