openlp/openlp/plugins/bibles/lib/importers/opensong.py

146 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2022 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
from openlp.plugins.bibles.lib.bibleimport import BibleImport
def get_text(element):
"""
Recursively get all text in an objectify element and its child elements.
:param element: An objectify element to get the text from
:return: The text content of the element (str)
"""
verse_text = ''
if element.text:
verse_text = element.text
for sub_element in element.iterchildren():
verse_text += get_text(sub_element)
if element.tail:
verse_text += element.tail
return verse_text
def parse_chapter_number(number, previous_number):
"""
Parse the chapter number
:param number: The raw data from the xml
:param previous_number: The previous chapter number
:return: Number of current chapter.
:rtype: int
"""
if number:
return int(number.split()[-1])
return previous_number + 1
class OpenSongBible(BibleImport):
"""
OpenSong Bible format importer class. This class is used to import Bibles from OpenSong's XML format.
"""
def parse_verse_number(self, number, previous_number):
"""
Parse the verse number retrieved from the xml
:param number: The raw data from the xml
:param previous_number: The previous verse number
:return: Number of current verse. (Int)
"""
if not number:
return previous_number + 1
try:
return int(number)
except ValueError:
verse_parts = number.split('-')
if len(verse_parts) > 1:
number = int(verse_parts[0])
return number
except TypeError:
self.log_warning('Illegal verse number: {verse_no}'.format(verse_no=str(number)))
return previous_number + 1
def process_books(self, books):
"""
Extract and create the books from the objectified xml
:param books: Objectified xml
:return: None
"""
for book in books:
if self.stop_import_flag:
break
db_book = self.find_and_create_book(str(book.attrib['n']), len(books), self.language_id)
self.process_chapters(db_book, book.c)
self.session.commit()
def process_chapters(self, book, chapters):
"""
Extract and create the chapters from the objectified xml for the book `book`
:param book: A database Book object to add the chapters to
:param chapters: Objectified xml containing chapters
:return: None
"""
chapter_number = 0
for chapter in chapters:
if self.stop_import_flag:
break
chapter_number = parse_chapter_number(chapter.attrib['n'], chapter_number)
self.set_current_chapter(book.name, chapter_number)
self.process_verses(book, chapter_number, chapter.v)
def process_verses(self, book, chapter_number, verses):
"""
Extract and create the verses from the objectified xml
:param book: A database Book object
:param chapter_number: The chapter number to add the verses to (int)
:param verses: Objectified xml containing verses
:return: None
"""
verse_number = 0
for verse in verses:
if self.stop_import_flag:
break
verse_number = self.parse_verse_number(verse.attrib['n'], verse_number)
self.create_verse(book.id, chapter_number, verse_number, get_text(verse))
def do_import(self, bible_name=None):
"""
Loads an Open Song Bible from a file.
:param bible_name: The name of the bible being imported
:return: True if import completed, False if import was unsuccessful
"""
self.log_debug('Starting OpenSong import from "{name}"'.format(name=self.file_path))
self.validate_xml_file(self.file_path, 'bible')
bible = self.parse_xml(self.file_path, use_objectify=True)
if bible is None:
return False
# No language info in the opensong format, so ask the user
self.language_id = self.get_language_id(bible_name=str(self.file_path))
if not self.language_id:
return False
self.process_books(bible.b)
return True