# CCLI SongSelect Import — Learnings ## [2026-05-10] Session Start ### Architecture Decisions - Manual paste + bookmarklet approach (NO server-side scraping — Cloudflare/ToS blocker) - CcliPasteParser is closure-injectable (mirrors ChurchToolsService pattern for testability) - All songs upserted via CcliImportService mirroring ProImportService::import() shape - Translation stored inline on SongSlide.text_content_translated (no separate model) - default_translation_language = APP-GLOBAL Setting (not per-user) ### Key Codebase Facts - Song.ccli_id is UNIQUE indexed nullable — primary CCLI match key - SongSlide: text_content (original), text_content_translated (translation) - Labels are GLOBAL (shared across all songs) — labels table with name + color - ProImportService::import() is the template for upsert (not upsertSong — that method doesn't exist) - SettingsController::AGENDA_KEYS constant whitelist for Settings KV - TranslationService::importFromText distributes lines preserving local slide line counts - ArrangementDialog.vue lines 488-532 = searchable song select (where CCLI buttons go) ### CCLI SongSelect "View Lyrics" Page Format - Title on first non-empty line - Section label as standalone line (e.g., "Verse 1", "Chorus") - Lyrics lines under each section - Footer: copyright (©), CCLI number (e.g., "CCLI # 1234567"), author ### Section Label Regex (English + German + variants) ``` /^(Verse|Chorus|Bridge|Pre-Chorus|Tag|Ending|Intro|Interlude|Outro|Misc|Strophe|Refrain|Brücke|Vorrefrain|Schluss|Zwischenspiel)\s*(\d+[a-z]?)?(\s*\((?:Repeat|Wdh\.?)\))?(\s*[xX]\s*\d+)?$/i ``` ### Language Mapping (EN ↔ DE) - Verse ↔ Strophe - Chorus ↔ Refrain - Bridge ↔ Brücke - Pre-Chorus ↔ Vorrefrain - Ending ↔ Schluss - Interlude ↔ Zwischenspiel ### Test Fixture Format Fixtures are synthetic CCLI-format text files. Format: ``` Test Song Title Test Artist Verse 1 Line 1 of verse Line 2 of verse Chorus Chorus line 1 Chorus line 2 © 2024 Test Publishing CCLI # 9999001 ``` ### Fixture Corpus Notes - Keep fixture titles/artists anonymized and numeric (`Test Song N`, `Test Artist N`) - Include both English and German section labels in the corpus so parser regex coverage stays broad - Add edge cases for missing footer pieces, whitespace, repeat markers, and suffix labels (`2a`, `x2`, `(Repeat)`) ### 2026-05-10 CCLI Label Utility Notes - `CcliLabels` works best with a fixed kind list in regexes; no locale config needed for EN/DE normalization. - `normalizeLabelName()` should map only known German kinds and preserve any numeric suffix. - `parseLabel()` can stay lightweight by returning `null` for non-labels and a small array for matched labels.