moved bible integration to local pocketbase backend and cleaned up unused code
This commit is contained in:
parent
49f9a9eb91
commit
3dd687ba30
|
@ -532,7 +532,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.1;
|
||||
MARKETING_VERSION = 1.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.rtsda.appr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
@ -574,7 +574,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.1;
|
||||
MARKETING_VERSION = 1.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.rtsda.appr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
|
|
@ -3,86 +3,156 @@ import Foundation
|
|||
@MainActor
|
||||
class BibleService {
|
||||
static let shared = BibleService()
|
||||
private let configService = ConfigService.shared
|
||||
private let baseURL = "https://api.scripture.api.bible/v1"
|
||||
private let pocketBaseService = PocketBaseService.shared
|
||||
|
||||
private init() {}
|
||||
|
||||
// API Response structures
|
||||
struct BibleAPIResponse: Codable {
|
||||
let data: VerseData
|
||||
}
|
||||
|
||||
struct VerseData: Codable {
|
||||
struct Verse: Identifiable, Codable {
|
||||
let id: String
|
||||
let orgId: String
|
||||
let bibleId: String
|
||||
let bookId: String
|
||||
let chapterId: String
|
||||
let reference: String
|
||||
let content: String
|
||||
let text: String
|
||||
let isActive: Bool
|
||||
|
||||
// The API returns HTML content, so we'll clean it up
|
||||
var cleanContent: String {
|
||||
return content
|
||||
.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression)
|
||||
.replacingOccurrences(of: """, with: "\"")
|
||||
.replacingOccurrences(of: "'", with: "'")
|
||||
.replacingOccurrences(of: "¶\\s*", with: "", options: .regularExpression)
|
||||
.replacingOccurrences(of: "^\\d+\\s*", with: "", options: .regularExpression) // Remove verse numbers at start
|
||||
.replacingOccurrences(of: "\\((.*?)\\)", with: "$1", options: .regularExpression) // Keep text inside parentheses
|
||||
.replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
|
||||
.trimmingCharacters(in: .whitespaces)
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case reference
|
||||
case text
|
||||
case isActive = "is_active"
|
||||
}
|
||||
}
|
||||
|
||||
struct VersesRecord: Codable {
|
||||
let collectionId: String
|
||||
let collectionName: String
|
||||
let created: String
|
||||
let id: String
|
||||
let updated: String
|
||||
let verses: VersesData
|
||||
|
||||
struct VersesData: Codable {
|
||||
let id: String
|
||||
let verses: [Verse]
|
||||
}
|
||||
}
|
||||
|
||||
private var cachedVerses: [Verse]?
|
||||
|
||||
func getRandomVerse() async throws -> (verse: String, reference: String) {
|
||||
// List of popular and uplifting Bible verses
|
||||
let references = [
|
||||
//"JER.29.11", "PRO.3.5", "PHP.4.13", "JOS.1.9",
|
||||
"PSA.23.1",
|
||||
//"ISA.40.31", "MAT.11.28", "ROM.8.28", "PSA.27.1", "PSA.46.10",
|
||||
//"JHN.3.16", "ROM.15.13",
|
||||
"2CO.5.7", //"DEU.31.6", "ROM.8.31",
|
||||
//"1JN.4.19", "PHP.4.6", "MAT.6.33", "HEB.11.1", "PSA.37.4"
|
||||
]
|
||||
let verses = try await getVerses()
|
||||
print("Total verses available: \(verses.count)")
|
||||
|
||||
// Randomly select a reference
|
||||
let randomReference = references.randomElement() ?? "JHN.3.16"
|
||||
|
||||
guard let apiKey = configService.bibleApiKey else {
|
||||
throw NSError(domain: "BibleService", code: -1, userInfo: [NSLocalizedDescriptionKey: "Bible API key not found"])
|
||||
guard !verses.isEmpty else {
|
||||
print("No verses available")
|
||||
throw NSError(domain: "BibleService", code: -1, userInfo: [NSLocalizedDescriptionKey: "No verses available"])
|
||||
}
|
||||
|
||||
// Construct the API URL
|
||||
let urlString = "\(baseURL)/bibles/de4e12af7f28f599-01/verses/\(randomReference)"
|
||||
var request = URLRequest(url: URL(string: urlString)!)
|
||||
request.addValue(apiKey, forHTTPHeaderField: "api-key")
|
||||
let randomVerse = verses.randomElement()!
|
||||
print("Selected random verse: \(randomVerse.reference)")
|
||||
return (verse: randomVerse.text, reference: randomVerse.reference)
|
||||
}
|
||||
|
||||
func getVerse(reference: String) async throws -> (verse: String, reference: String) {
|
||||
print("Looking up verse with reference: \(reference)")
|
||||
|
||||
// Convert API-style reference (e.g., "JER.29.11") to display format ("Jeremiah 29:11")
|
||||
let displayReference = reference
|
||||
.replacingOccurrences(of: "\\.", with: " ", options: .regularExpression)
|
||||
.replacingOccurrences(of: "([A-Z]+)", with: "$1 ", options: .regularExpression)
|
||||
.trimmingCharacters(in: .whitespaces)
|
||||
|
||||
print("Converted reference to: \(displayReference)")
|
||||
|
||||
let verses = try await getVerses()
|
||||
print("Found \(verses.count) verses")
|
||||
|
||||
if let verse = verses.first(where: { $0.reference.lowercased() == displayReference.lowercased() }) {
|
||||
print("Found matching verse: \(verse.reference)")
|
||||
return (verse: verse.text, reference: verse.reference)
|
||||
}
|
||||
|
||||
print("No matching verse found for reference: \(displayReference)")
|
||||
throw NSError(domain: "BibleService", code: -1, userInfo: [NSLocalizedDescriptionKey: "Verse not found"])
|
||||
}
|
||||
|
||||
private func getVerses() async throws -> [Verse] {
|
||||
// Return cached verses if available
|
||||
if let cached = cachedVerses {
|
||||
print("Returning cached verses")
|
||||
return cached
|
||||
}
|
||||
|
||||
print("Fetching verses from PocketBase")
|
||||
// Fetch from PocketBase
|
||||
let endpoint = "\(PocketBaseService.shared.baseURL)/bible_verses/records/nkf01o1q3456flr"
|
||||
|
||||
guard let url = URL(string: endpoint) else {
|
||||
print("Invalid URL: \(endpoint)")
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
print("Making request to: \(endpoint)")
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
|
||||
// Log raw response
|
||||
if let rawResponse = String(data: data, encoding: .utf8) {
|
||||
print("Raw Bible API Response:")
|
||||
print(rawResponse)
|
||||
print("\n")
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
print("Invalid response type")
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
// Check for successful response
|
||||
guard let httpResponse = response as? HTTPURLResponse,
|
||||
(200...299).contains(httpResponse.statusCode) else {
|
||||
throw NSError(domain: "BibleService", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to fetch verse"])
|
||||
print("Response status code: \(httpResponse.statusCode)")
|
||||
|
||||
guard httpResponse.statusCode == 200 else {
|
||||
if let errorString = String(data: data, encoding: .utf8) {
|
||||
print("Error response from server: \(errorString)")
|
||||
}
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
// Print raw response for debugging
|
||||
if let rawResponse = String(data: data, encoding: .utf8) {
|
||||
print("Raw response from PocketBase:")
|
||||
print(rawResponse)
|
||||
}
|
||||
|
||||
let decoder = JSONDecoder()
|
||||
let apiResponse = try decoder.decode(BibleAPIResponse.self, from: data)
|
||||
|
||||
// Log cleaned content
|
||||
print("Cleaned verse content:")
|
||||
print(apiResponse.data.cleanContent)
|
||||
print("\nReference:", apiResponse.data.reference)
|
||||
print("\n")
|
||||
|
||||
return (verse: apiResponse.data.cleanContent, reference: apiResponse.data.reference)
|
||||
do {
|
||||
let versesRecord = try decoder.decode(VersesRecord.self, from: data)
|
||||
|
||||
// Cache the verses
|
||||
cachedVerses = versesRecord.verses.verses
|
||||
print("Successfully fetched and cached \(versesRecord.verses.verses.count) verses")
|
||||
|
||||
return versesRecord.verses.verses
|
||||
} catch {
|
||||
print("Failed to decode response: \(error)")
|
||||
if let decodingError = error as? DecodingError {
|
||||
switch decodingError {
|
||||
case .keyNotFound(let key, let context):
|
||||
print("Missing key: \(key.stringValue) in \(context.debugDescription)")
|
||||
case .typeMismatch(let type, let context):
|
||||
print("Type mismatch: expected \(type) in \(context.debugDescription)")
|
||||
case .valueNotFound(let type, let context):
|
||||
print("Value not found: expected \(type) in \(context.debugDescription)")
|
||||
case .dataCorrupted(let context):
|
||||
print("Data corrupted: \(context.debugDescription)")
|
||||
@unknown default:
|
||||
print("Unknown decoding error")
|
||||
}
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func testAllVerses() async throws {
|
||||
print("\n=== Testing All Verses ===\n")
|
||||
let verses = try await getVerses()
|
||||
for verse in verses {
|
||||
print("Reference: \(verse.reference)")
|
||||
print("Verse: \(verse.text)")
|
||||
print("-------------------\n")
|
||||
}
|
||||
print("=== Test Complete ===\n")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ struct Bulletin: Identifiable, Codable {
|
|||
|
||||
class PocketBaseService {
|
||||
static let shared = PocketBaseService()
|
||||
private let baseURL = "https://pocketbase.rockvilletollandsda.church/api/collections"
|
||||
let baseURL = "https://pocketbase.rockvilletollandsda.church/api/collections"
|
||||
|
||||
private init() {}
|
||||
|
||||
|
|
|
@ -495,7 +495,7 @@ struct MoreView: View {
|
|||
fallbackURL: AppAvailabilityService.AppStoreURLs.hymnal
|
||||
)
|
||||
} label: {
|
||||
Label("SDA Hymnal", systemImage: "music.note")
|
||||
Label("Adventist Hymnal", systemImage: "music.note")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
125
bible_verses.json
Normal file
125
bible_verses.json
Normal file
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"id": "verses",
|
||||
"verses": [
|
||||
{
|
||||
"id": "1",
|
||||
"reference": "Jeremiah 29:11",
|
||||
"text": "For I know the thoughts that I think toward you, saith the LORD, thoughts of peace, and not of evil, to give you an expected end.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"reference": "Proverbs 3:5",
|
||||
"text": "Trust in the LORD with all thine heart; and lean not unto thine own understanding.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"reference": "Philippians 4:13",
|
||||
"text": "I can do all things through Christ which strengtheneth me.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"reference": "John 3:16",
|
||||
"text": "For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"reference": "Romans 8:28",
|
||||
"text": "And we know that all things work together for good to them that love God, to them who are the called according to his purpose.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"reference": "Matthew 6:33",
|
||||
"text": "But seek ye first the kingdom of God, and his righteousness; and all these things shall be added unto you.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"reference": "Isaiah 41:10",
|
||||
"text": "Fear thou not; for I am with thee: be not dismayed; for I am thy God: I will strengthen thee; yea, I will help thee; yea, I will uphold thee with the right hand of my righteousness.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
"reference": "Joshua 1:9",
|
||||
"text": "Have not I commanded thee? Be strong and of a good courage; be not afraid, neither be thou dismayed: for the LORD thy God is with thee whithersoever thou goest.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "9",
|
||||
"reference": "Psalm 23:1",
|
||||
"text": "The LORD is my shepherd; I shall not want.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
"reference": "Psalm 27:1",
|
||||
"text": "The LORD is my light and my salvation; whom shall I fear? the LORD is the strength of my life; of whom shall I be afraid?",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
"reference": "Psalm 46:1",
|
||||
"text": "God is our refuge and strength, a very present help in trouble.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
"reference": "Psalm 91:1",
|
||||
"text": "He that dwelleth in the secret place of the most High shall abide under the shadow of the Almighty.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "13",
|
||||
"reference": "Psalm 119:105",
|
||||
"text": "Thy word is a lamp unto my feet, and a light unto my path.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "14",
|
||||
"reference": "Psalm 121:1",
|
||||
"text": "I will lift up mine eyes unto the hills, from whence cometh my help.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "15",
|
||||
"reference": "Psalm 139:14",
|
||||
"text": "I will praise thee; for I am fearfully and wonderfully made: marvellous are thy works; and that my soul knoweth right well.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "16",
|
||||
"reference": "Proverbs 16:3",
|
||||
"text": "Commit thy works unto the LORD, and thy thoughts shall be established.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "17",
|
||||
"reference": "Isaiah 40:31",
|
||||
"text": "But they that wait upon the LORD shall renew their strength; they shall mount up with wings as eagles; they shall run, and not be weary; and they shall walk, and not faint.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "18",
|
||||
"reference": "Matthew 11:28",
|
||||
"text": "Come unto me, all ye that labour and are heavy laden, and I will give you rest.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "19",
|
||||
"reference": "John 14:27",
|
||||
"text": "Peace I leave with you, my peace I give unto you: not as the world giveth, give I unto you. Let not your heart be troubled, neither let it be afraid.",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"id": "20",
|
||||
"reference": "Romans 12:2",
|
||||
"text": "And be not conformed to this world: but be ye transformed by the renewing of your mind, that ye may prove what is that good, and acceptable, and perfect, will of God.",
|
||||
"is_active": true
|
||||
}
|
||||
]
|
||||
}
|
107
test_verses.swift
Normal file
107
test_verses.swift
Normal file
|
@ -0,0 +1,107 @@
|
|||
import Foundation
|
||||
|
||||
class PocketBaseService {
|
||||
static let shared = PocketBaseService()
|
||||
let baseURL = "https://pocketbase.rockvilletollandsda.church/api/collections"
|
||||
private init() {}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class BibleService {
|
||||
static let shared = BibleService()
|
||||
private let pocketBaseService = PocketBaseService.shared
|
||||
|
||||
private init() {}
|
||||
|
||||
struct Verse: Identifiable, Codable {
|
||||
let id: String
|
||||
let reference: String
|
||||
let text: String
|
||||
let isActive: Bool
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case reference
|
||||
case text
|
||||
case isActive = "is_active"
|
||||
}
|
||||
}
|
||||
|
||||
struct VersesRecord: Codable {
|
||||
let collectionId: String
|
||||
let collectionName: String
|
||||
let created: String
|
||||
let id: String
|
||||
let updated: String
|
||||
let verses: VersesData
|
||||
|
||||
struct VersesData: Codable {
|
||||
let id: String
|
||||
let verses: [Verse]
|
||||
}
|
||||
}
|
||||
|
||||
private var cachedVerses: [Verse]?
|
||||
|
||||
private func getVerses() async throws -> [Verse] {
|
||||
print("Fetching verses from PocketBase")
|
||||
let endpoint = "\(PocketBaseService.shared.baseURL)/bible_verses/records/nkf01o1q3456flr"
|
||||
|
||||
guard let url = URL(string: endpoint) else {
|
||||
print("Invalid URL: \(endpoint)")
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
print("Making request to: \(endpoint)")
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
print("Invalid response type")
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
print("Response status code: \(httpResponse.statusCode)")
|
||||
|
||||
guard httpResponse.statusCode == 200 else {
|
||||
if let errorString = String(data: data, encoding: .utf8) {
|
||||
print("Error response from server: \(errorString)")
|
||||
}
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
let decoder = JSONDecoder()
|
||||
let versesRecord = try decoder.decode(VersesRecord.self, from: data)
|
||||
return versesRecord.verses.verses
|
||||
}
|
||||
|
||||
func testAllVerses() async throws {
|
||||
print("\n=== Testing All Verses ===\n")
|
||||
let verses = try await getVerses()
|
||||
for verse in verses {
|
||||
print("Reference: \(verse.reference)")
|
||||
print("Text: \(verse.text)")
|
||||
print("-------------------\n")
|
||||
}
|
||||
print("=== Test Complete ===\n")
|
||||
}
|
||||
}
|
||||
|
||||
print("Starting Bible Verses Test...")
|
||||
|
||||
// Create a semaphore to signal when the task is complete
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await BibleService.shared.testAllVerses()
|
||||
} catch {
|
||||
print("Error testing verses: \(error)")
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
|
||||
// Wait for the task to complete
|
||||
semaphore.wait()
|
Loading…
Reference in a new issue