RTSDA-Website/church-core/src/utils/scripture.rs

164 lines
5.9 KiB
Rust

use regex::Regex;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScriptureSection {
pub verse: String,
pub reference: String,
}
/// Format raw scripture text into structured sections with verses and references
pub fn format_scripture_text(text: &str) -> Vec<ScriptureSection> {
// Handle single-line format where verse and reference are together
if text.contains(" KJV") && !text.contains('\n') {
// Single line format: "verse text. Book chapter:verse KJV"
if let Some(kjv_pos) = text.rfind(" KJV") {
let before_kjv = &text[..kjv_pos];
// Find the last period or other punctuation that separates verse from reference
if let Some(last_period) = before_kjv.rfind('.') {
if let Some(reference_start) = before_kjv[last_period..].find(char::is_alphabetic) {
let actual_start = last_period + reference_start;
let verse_text = format!("{}.", &before_kjv[..last_period]);
let reference = format!("{} KJV", &before_kjv[actual_start..]);
return vec![ScriptureSection {
verse: verse_text.trim().to_string(),
reference: reference.trim().to_string(),
}];
}
}
}
// Fallback: treat entire text as verse with no separate reference
return vec![ScriptureSection {
verse: text.to_string(),
reference: String::new(),
}];
}
// Multi-line format (original logic)
let sections: Vec<&str> = text.split('\n').collect();
let mut formatted_sections = Vec::new();
let mut current_verse = String::new();
for section in sections {
let trimmed = section.trim();
if trimmed.is_empty() {
continue;
}
// Check if this line is a reference (contains "KJV" at the end)
if trimmed.ends_with("KJV") {
// This is a reference for the verse we just accumulated
if !current_verse.is_empty() {
formatted_sections.push(ScriptureSection {
verse: current_verse.clone(),
reference: trimmed.to_string(),
});
current_verse.clear(); // Reset for next verse
}
} else {
// This is verse text
if !current_verse.is_empty() {
current_verse.push(' ');
}
current_verse.push_str(trimmed);
}
}
// Add any remaining verse without a reference
if !current_verse.is_empty() {
formatted_sections.push(ScriptureSection {
verse: current_verse,
reference: String::new(),
});
}
formatted_sections
}
/// Extract scripture references from text (e.g., "Joel 2:28 KJV" patterns)
pub fn extract_scripture_references(text: &str) -> String {
let pattern = r"([1-3]?\s*[A-Za-z]+\s+\d+:\d+(?:-\d+)?)\s+KJV";
match Regex::new(pattern) {
Ok(regex) => {
let references: Vec<String> = regex
.captures_iter(text)
.filter_map(|cap| cap.get(1).map(|m| m.as_str().trim().to_string()))
.collect();
if references.is_empty() {
"Scripture Reading".to_string()
} else {
references.join(", ")
}
}
Err(_) => "Scripture Reading".to_string(),
}
}
/// Create standardized share text for sermons
pub fn create_sermon_share_text(title: &str, speaker: &str, video_url: Option<&str>, audio_url: Option<&str>) -> Vec<String> {
let mut items = Vec::new();
// Create share text
let share_text = format!("Check out this sermon: \"{}\" by {}", title, speaker);
items.push(share_text);
// Add video URL if available, otherwise audio URL
if let Some(url) = video_url {
items.push(url.to_string());
} else if let Some(url) = audio_url {
items.push(url.to_string());
}
items
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_line_scripture_format() {
let input = "And it shall come to pass afterward, that I will pour out my spirit upon all flesh. Joel 2:28 KJV";
let result = format_scripture_text(input);
assert_eq!(result.len(), 1);
assert_eq!(result[0].verse, "And it shall come to pass afterward, that I will pour out my spirit upon all flesh.");
assert_eq!(result[0].reference, "Joel 2:28 KJV");
}
#[test]
fn test_multi_line_scripture_format() {
let input = "And it shall come to pass afterward, that I will pour out my spirit upon all flesh\nJoel 2:28 KJV\nQuench not the Spirit. Despise not prophesyings.\n1 Thessalonians 5:19-21 KJV";
let result = format_scripture_text(input);
assert_eq!(result.len(), 2);
assert_eq!(result[0].verse, "And it shall come to pass afterward, that I will pour out my spirit upon all flesh");
assert_eq!(result[0].reference, "Joel 2:28 KJV");
assert_eq!(result[1].verse, "Quench not the Spirit. Despise not prophesyings.");
assert_eq!(result[1].reference, "1 Thessalonians 5:19-21 KJV");
}
#[test]
fn test_extract_scripture_references() {
let input = "Some text with Joel 2:28 KJV and 1 Thessalonians 5:19-21 KJV references";
let result = extract_scripture_references(input);
assert_eq!(result, "Joel 2:28, 1 Thessalonians 5:19-21");
}
#[test]
fn test_create_sermon_share_text() {
let result = create_sermon_share_text(
"Test Sermon",
"John Doe",
Some("https://example.com/video"),
Some("https://example.com/audio")
);
assert_eq!(result.len(), 2);
assert_eq!(result[0], "Check out this sermon: \"Test Sermon\" by John Doe");
assert_eq!(result[1], "https://example.com/video");
}
}