Source code for openlp.plugins.songs.lib.importers.worshipassistant

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4

###############################################################################
# OpenLP - Open Source Lyrics Projection                                      #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 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; version 2 of the License.                              #
#                                                                             #
# 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, write to the Free Software Foundation, Inc., 59  #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
###############################################################################
"""
The :mod:`worshipassistant` module provides the functionality for importing
Worship Assistant songs into the OpenLP database.
"""
import chardet
import csv
import logging
import re

from openlp.core.common import translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.importers.songimport import SongImport

log = logging.getLogger(__name__)

EMPTY_STR = 'NULL'


[docs]class WorshipAssistantImport(SongImport): """ The :class:`WorshipAssistantImport` class provides the ability to import songs from Worship Assistant, via a dump of the database to a CSV file. The following fields are in the exported CSV file: * ``SONGNR`` Song ID (Discarded by importer) * ``TITLE`` Song title * ``AUTHOR`` Song author. * ``COPYRIGHT`` Copyright information * ``FIRSTLINE`` Unknown (Discarded by importer) * ``PRIKEY`` Primary chord key (Discarded by importer) * ``ALTKEY`` Alternate chord key (Discarded by importer) * ``TEMPO`` Tempo (Discarded by importer) * ``FOCUS`` Unknown (Discarded by importer) * ``THEME`` Theme (Discarded by importer) * ``SCRIPTURE`` Associated scripture (Discarded by importer) * ``ACTIVE`` Boolean value (Discarded by importer) * ``SONGBOOK`` Boolean value (Discarded by importer) * ``TIMESIG`` Unknown (Discarded by importer) * ``INTRODUCED`` Date the song was created (Discarded by importer) * ``LASTUSED`` Date the song was last used (Discarded by importer) * ``TIMESUSED`` How many times the song was used (Discarded by importer) * ``CCLINR`` CCLI Number * ``USER1`` User Field 1 (Discarded by importer) * ``USER2`` User Field 2 (Discarded by importer) * ``USER3`` User Field 3 (Discarded by importer) * ``USER4`` User Field 4 (Discarded by importer) * ``USER5`` User Field 5 (Discarded by importer) * ``ROADMAP`` Verse order used for the presentation * ``FILELINK1`` Associated file 1 (Discarded by importer) * ``OVERMAP`` Verse order used for printing (Discarded by importer) * ``FILELINK2`` Associated file 2 (Discarded by importer) * ``LYRICS`` The song lyrics used for printing (Discarded by importer, LYRICS2 is used instead) * ``INFO`` Unknown (Discarded by importer) * ``LYRICS2`` The song lyrics used for the presentation * ``BACKGROUND`` Custom background (Discarded by importer) """
[docs] def do_import(self): """ Receive a CSV file to import. """ # Get encoding detect_file = open(self.import_source, 'rb') detect_content = detect_file.read() details = chardet.detect(detect_content) detect_file.close() songs_file = open(self.import_source, 'r', encoding=details['encoding']) songs_reader = csv.DictReader(songs_file, escapechar='\\') try: records = list(songs_reader) except csv.Error as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), translate('SongsPlugin.WorshipAssistantImport', 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e)) return num_records = len(records) log.info('{count} records found in CSV file'.format(count=num_records)) self.import_wizard.progress_bar.setMaximum(num_records) # Create regex to strip html tags re_html_strip = re.compile(r'<[^>]+>') for index, record in enumerate(records, 1): if self.stop_import_flag: return # Ensure that all keys are uppercase record = dict((field.upper(), value) for field, value in record.items()) # The CSV file has a line in the middle of the file where the headers are repeated. # We need to skip this line. if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': continue self.set_defaults() verse_order_list = [] try: self.title = record['TITLE'] if record['AUTHOR'] != EMPTY_STR: self.parse_author(record['AUTHOR']) if record['COPYRIGHT'] != EMPTY_STR: self.add_copyright(record['COPYRIGHT']) if record['CCLINR'] != EMPTY_STR: self.ccli_number = record['CCLINR'] if record['ROADMAP'] != EMPTY_STR: verse_order_list = [x.strip() for x in record['ROADMAP'].split(',')] lyrics = record['LYRICS2'] except UnicodeDecodeError as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record {count:d}').format(count=index), translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: {error}').format(error=e)) continue except TypeError as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'File not valid WorshipAssistant CSV format.'), 'TypeError: {error}'.format(error=e)) return verse = '' used_verses = [] verse_id = VerseType.tags[VerseType.Verse] + '1' for line in lyrics.splitlines(): if line.startswith('['): # verse marker # Add previous verse if verse: # remove trailing linebreak, part of the WA syntax self.add_verse(verse[:-1], verse_id) used_verses.append(verse_id) verse = '' # drop the square brackets right_bracket = line.find(']') content = line[1:right_bracket].lower() match = re.match('(\D*)(\d+)', content) if match is not None: verse_tag = match.group(1) verse_num = match.group(2) else: # otherwise we assume number 1 and take the whole prefix as the verse tag verse_tag = content verse_num = '1' verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 verse_tag = VerseType.tags[verse_index] # Update verse order when the verse name has changed verse_id = verse_tag + verse_num # Make sure we've not choosen an id already used while verse_id in verse_order_list and content in verse_order_list: verse_num = str(int(verse_num) + 1) verse_id = verse_tag + verse_num if content != verse_id: for i in range(len(verse_order_list)): if verse_order_list[i].lower() == content.lower(): verse_order_list[i] = verse_id else: # add line text to verse. Strip out html verse += re_html_strip.sub('', line) + '\n' if verse: # remove trailing linebreak, part of the WA syntax if verse.endswith('\n\n'): verse = verse[:-1] self.add_verse(verse, verse_id) used_verses.append(verse_id) if verse_order_list: # Use the verse order in the import, but remove entries that doesn't have a text cleaned_verse_order_list = [] for verse in verse_order_list: if verse in used_verses: cleaned_verse_order_list.append(verse) self.verse_order_list = cleaned_verse_order_list if not self.finish(): self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record {count:d}').format(count=index) + (': "' + self.title + '"' if self.title else '')) songs_file.close()