# -*- 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()