2011-01-12 08:59:14 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2013-01-06 17:25:49 +00:00
|
|
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
2011-01-12 08:59:14 +00:00
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
# OpenLP - Open Source Lyrics Projection #
|
|
|
|
# --------------------------------------------------------------------------- #
|
2015-12-31 22:46:06 +00:00
|
|
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
2011-01-12 08:59:14 +00:00
|
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
# 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 #
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import re
|
|
|
|
|
2011-04-17 15:47:02 +00:00
|
|
|
from lxml import etree, objectify
|
|
|
|
|
|
|
|
from openlp.plugins.songs.lib import VerseType
|
2014-07-04 09:31:06 +00:00
|
|
|
from openlp.plugins.songs.lib.importers.songimport import SongImport
|
2011-01-12 08:59:14 +00:00
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
|
2011-12-31 14:18:05 +00:00
|
|
|
class EasySlidesImport(SongImport):
|
2011-01-12 08:59:14 +00:00
|
|
|
"""
|
2011-12-31 14:18:05 +00:00
|
|
|
Import songs exported from EasySlides
|
2011-01-12 08:59:14 +00:00
|
|
|
|
2011-01-18 18:53:09 +00:00
|
|
|
The format example is here:
|
2015-09-08 19:13:59 +00:00
|
|
|
http://wiki.openlp.org/Development:EasySlides\_-_Song_Data_Format
|
2011-01-12 08:59:14 +00:00
|
|
|
"""
|
|
|
|
def __init__(self, manager, **kwargs):
|
|
|
|
"""
|
|
|
|
Initialise the class.
|
|
|
|
"""
|
2014-03-29 13:31:28 +00:00
|
|
|
super(EasySlidesImport, self).__init__(manager, **kwargs)
|
2011-01-12 08:59:14 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
def do_import(self):
|
2013-08-31 18:17:38 +00:00
|
|
|
log.info('Importing EasySlides XML file %s', self.import_source)
|
2011-01-17 20:47:46 +00:00
|
|
|
parser = etree.XMLParser(remove_blank_text=True)
|
2013-03-07 08:05:43 +00:00
|
|
|
parsed_file = etree.parse(self.import_source, parser)
|
2013-07-13 15:38:14 +00:00
|
|
|
xml = etree.tostring(parsed_file).decode()
|
2011-01-17 20:47:46 +00:00
|
|
|
song_xml = objectify.fromstring(xml)
|
2013-03-07 08:05:43 +00:00
|
|
|
self.import_wizard.progress_bar.setMaximum(len(song_xml.Item))
|
2011-01-17 20:47:46 +00:00
|
|
|
for song in song_xml.Item:
|
2013-02-07 11:33:47 +00:00
|
|
|
if self.stop_import_flag:
|
2011-04-17 15:47:02 +00:00
|
|
|
return
|
2014-03-06 20:40:08 +00:00
|
|
|
self._parse_song(song)
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
def _parse_song(self, song):
|
2011-01-17 20:47:46 +00:00
|
|
|
self._success = True
|
2013-08-31 18:17:38 +00:00
|
|
|
self._add_unicode_attribute('title', song.Title1, True)
|
|
|
|
if hasattr(song, 'Title2'):
|
2014-03-08 19:58:58 +00:00
|
|
|
self._add_unicode_attribute('alternate_title', song.Title2)
|
2013-08-31 18:17:38 +00:00
|
|
|
if hasattr(song, 'SongNumber'):
|
2014-03-05 18:58:22 +00:00
|
|
|
self._add_unicode_attribute('song_number', song.SongNumber)
|
|
|
|
if self.song_number == '0':
|
|
|
|
self.song_number = ''
|
2016-01-08 21:42:36 +00:00
|
|
|
if hasattr(song, 'Writer'):
|
|
|
|
self._add_authors(song.Writer)
|
2013-08-31 18:17:38 +00:00
|
|
|
if hasattr(song, 'Copyright'):
|
2013-03-07 08:05:43 +00:00
|
|
|
self._add_copyright(song.Copyright)
|
2013-08-31 18:17:38 +00:00
|
|
|
if hasattr(song, 'LicenceAdmin1'):
|
2013-03-07 08:05:43 +00:00
|
|
|
self._add_copyright(song.LicenceAdmin1)
|
2013-08-31 18:17:38 +00:00
|
|
|
if hasattr(song, 'LicenceAdmin2'):
|
2013-03-07 08:05:43 +00:00
|
|
|
self._add_copyright(song.LicenceAdmin2)
|
2013-08-31 18:17:38 +00:00
|
|
|
if hasattr(song, 'BookReference'):
|
2014-03-05 18:58:22 +00:00
|
|
|
self._add_unicode_attribute('song_book_name', song.BookReference)
|
2014-03-06 20:40:08 +00:00
|
|
|
self._parse_and_add_lyrics(song)
|
2011-04-17 15:47:02 +00:00
|
|
|
if self._success:
|
2011-04-18 16:46:22 +00:00
|
|
|
if not self.finish():
|
2014-03-05 18:58:22 +00:00
|
|
|
self.log_error(song.Title1 if song.Title1 else '')
|
2011-04-18 16:46:22 +00:00
|
|
|
else:
|
2014-03-05 18:58:22 +00:00
|
|
|
self.set_defaults()
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2013-03-07 08:05:43 +00:00
|
|
|
def _add_unicode_attribute(self, self_attribute, import_attribute, mandatory=False):
|
2011-01-21 21:21:09 +00:00
|
|
|
"""
|
|
|
|
Add imported values to the song model converting them to unicode at the
|
2011-02-25 17:05:01 +00:00
|
|
|
same time. If the unicode decode fails or a mandatory attribute is not
|
2011-01-21 21:21:09 +00:00
|
|
|
present _success is set to False so the importer can react
|
|
|
|
appropriately.
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
:param self_attribute: The attribute in the song model to populate.
|
|
|
|
:param import_attribute: The imported value to convert to unicode and save to the song.
|
|
|
|
:param mandatory: Signals that this attribute must exist in a valid song.
|
2011-01-21 21:21:09 +00:00
|
|
|
"""
|
2011-01-17 20:47:46 +00:00
|
|
|
try:
|
2013-08-31 18:17:38 +00:00
|
|
|
setattr(self, self_attribute, str(import_attribute).strip())
|
2011-01-17 22:27:25 +00:00
|
|
|
except UnicodeDecodeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('UnicodeDecodeError decoding %s' % import_attribute)
|
2011-01-17 23:16:30 +00:00
|
|
|
self._success = False
|
2011-01-17 22:27:25 +00:00
|
|
|
except AttributeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('No attribute %s' % import_attribute)
|
2011-01-21 21:21:09 +00:00
|
|
|
if mandatory:
|
|
|
|
self._success = False
|
2011-01-17 20:47:46 +00:00
|
|
|
|
2016-01-08 21:42:36 +00:00
|
|
|
def _add_authors(self, writer):
|
2011-01-17 20:47:46 +00:00
|
|
|
try:
|
2016-01-08 21:42:36 +00:00
|
|
|
self.parse_author(str(writer))
|
|
|
|
except UnicodeDecodeError as e:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('Unicode decode error while decoding Writer')
|
2011-01-17 23:16:30 +00:00
|
|
|
self._success = False
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2013-03-07 08:05:43 +00:00
|
|
|
def _add_copyright(self, element):
|
2011-02-01 00:33:50 +00:00
|
|
|
"""
|
2014-03-06 20:40:08 +00:00
|
|
|
Add a piece of copyright to the total copyright information for the song.
|
2011-02-01 00:33:50 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
:param element: The imported variable to get the data from.
|
2011-02-01 00:33:50 +00:00
|
|
|
"""
|
2011-01-17 20:47:46 +00:00
|
|
|
try:
|
2014-03-05 18:58:22 +00:00
|
|
|
self.add_copyright(str(element).strip())
|
2011-01-17 22:27:25 +00:00
|
|
|
except UnicodeDecodeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('Unicode error on decoding copyright: %s' % element)
|
2011-01-17 23:16:30 +00:00
|
|
|
self._success = False
|
2011-01-17 22:27:25 +00:00
|
|
|
except AttributeError:
|
2011-01-17 20:47:46 +00:00
|
|
|
pass
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
def _parse_and_add_lyrics(self, song):
|
|
|
|
"""
|
|
|
|
Process the song lyrics
|
|
|
|
|
|
|
|
:param song: The song details
|
|
|
|
"""
|
2011-01-17 20:47:46 +00:00
|
|
|
try:
|
2013-08-31 18:17:38 +00:00
|
|
|
lyrics = str(song.Contents).strip()
|
2011-01-17 22:27:25 +00:00
|
|
|
except UnicodeDecodeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('Unicode decode error while decoding Contents')
|
2011-01-17 23:16:30 +00:00
|
|
|
self._success = False
|
2011-01-17 22:27:25 +00:00
|
|
|
except AttributeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('no Contents')
|
2011-01-17 20:47:46 +00:00
|
|
|
self._success = False
|
2013-08-31 18:17:38 +00:00
|
|
|
lines = lyrics.split('\n')
|
2011-01-17 20:47:46 +00:00
|
|
|
# we go over all lines first, to determine information,
|
2011-01-17 16:21:46 +00:00
|
|
|
# which tells us how to parse verses later
|
2014-03-06 20:40:08 +00:00
|
|
|
region_lines = {}
|
|
|
|
separator_lines = 0
|
2011-01-17 22:27:25 +00:00
|
|
|
for line in lines:
|
|
|
|
line = line.strip()
|
2012-04-29 15:31:56 +00:00
|
|
|
if not line:
|
2011-01-17 22:27:25 +00:00
|
|
|
continue
|
2013-08-31 18:17:38 +00:00
|
|
|
elif line[1:7] == 'region':
|
2011-01-17 22:27:25 +00:00
|
|
|
# this is region separator, probably [region 2]
|
2014-03-06 20:40:08 +00:00
|
|
|
region = self._extract_region(line)
|
|
|
|
region_lines[region] = 1 + region_lines.get(region, 0)
|
2013-08-31 18:17:38 +00:00
|
|
|
elif line[0] == '[':
|
2014-03-06 20:40:08 +00:00
|
|
|
separator_lines += 1
|
2011-01-17 16:21:46 +00:00
|
|
|
# if the song has separators
|
2014-03-06 20:40:08 +00:00
|
|
|
separators = (separator_lines > 0)
|
2011-01-17 19:09:35 +00:00
|
|
|
# the number of different regions in song - 1
|
2014-03-06 20:40:08 +00:00
|
|
|
if len(region_lines) > 1:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.info('EasySlidesImport: the file contained a song named "%s"'
|
2014-03-06 20:40:08 +00:00
|
|
|
'with more than two regions, but only two regions are tested, encountered regions were: %s',
|
|
|
|
self.title, ','.join(list(region_lines.keys())))
|
2011-01-17 16:21:46 +00:00
|
|
|
# if the song has regions
|
2014-03-06 20:40:08 +00:00
|
|
|
regions = (len(region_lines) > 0)
|
2011-01-17 19:09:35 +00:00
|
|
|
# if the regions are inside verses
|
2014-03-06 20:40:08 +00:00
|
|
|
regions_in_verses = (regions and region_lines[list(region_lines.keys())[0]] > 1)
|
2011-01-17 22:27:25 +00:00
|
|
|
MarkTypes = {
|
2013-08-31 18:17:38 +00:00
|
|
|
'CHORUS': VerseType.tags[VerseType.Chorus],
|
|
|
|
'VERSE': VerseType.tags[VerseType.Verse],
|
|
|
|
'INTRO': VerseType.tags[VerseType.Intro],
|
|
|
|
'ENDING': VerseType.tags[VerseType.Ending],
|
|
|
|
'BRIDGE': VerseType.tags[VerseType.Bridge],
|
|
|
|
'PRECHORUS': VerseType.tags[VerseType.PreChorus]
|
2011-04-17 15:47:02 +00:00
|
|
|
}
|
2011-01-12 15:10:20 +00:00
|
|
|
verses = {}
|
2011-01-17 19:09:35 +00:00
|
|
|
# list as [region, versetype, versenum, instance]
|
2011-01-12 15:10:20 +00:00
|
|
|
our_verse_order = []
|
2014-03-06 20:40:08 +00:00
|
|
|
default_region = '1'
|
|
|
|
reg = default_region
|
2011-01-17 16:21:46 +00:00
|
|
|
verses[reg] = {}
|
2011-01-17 19:09:35 +00:00
|
|
|
# instance differentiates occurrences of same verse tag
|
2013-08-31 18:17:38 +00:00
|
|
|
vt = 'V'
|
|
|
|
vn = '1'
|
2011-01-17 23:16:30 +00:00
|
|
|
inst = 1
|
2011-01-17 22:27:25 +00:00
|
|
|
for line in lines:
|
|
|
|
line = line.strip()
|
2012-04-29 15:31:56 +00:00
|
|
|
if not line:
|
2011-01-17 16:21:46 +00:00
|
|
|
if separators:
|
|
|
|
# separators are used, so empty line means slide break
|
|
|
|
# inside verse
|
2014-03-06 20:40:08 +00:00
|
|
|
if self._list_has(verses, [reg, vt, vn, inst]):
|
2013-02-04 21:26:27 +00:00
|
|
|
inst += 1
|
2011-01-17 16:21:46 +00:00
|
|
|
else:
|
|
|
|
# separators are not used, so empty line starts a new verse
|
2013-08-31 18:17:38 +00:00
|
|
|
vt = 'V'
|
2012-04-29 15:31:56 +00:00
|
|
|
vn = len(verses[reg].get(vt, {})) + 1
|
2011-01-17 16:21:46 +00:00
|
|
|
inst = 1
|
2013-08-31 18:17:38 +00:00
|
|
|
elif line[0:7] == '[region':
|
2014-03-06 20:40:08 +00:00
|
|
|
reg = self._extract_region(line)
|
2012-04-29 15:31:56 +00:00
|
|
|
verses.setdefault(reg, {})
|
2014-03-06 20:40:08 +00:00
|
|
|
if not regions_in_verses:
|
2013-08-31 18:17:38 +00:00
|
|
|
vt = 'V'
|
|
|
|
vn = '1'
|
2011-01-17 23:16:30 +00:00
|
|
|
inst = 1
|
2013-08-31 18:17:38 +00:00
|
|
|
elif line[0] == '[':
|
2011-01-17 16:21:46 +00:00
|
|
|
# this is a normal section marker
|
2013-08-31 18:17:38 +00:00
|
|
|
marker = line[1:line.find(']')].upper()
|
|
|
|
vn = '1'
|
2011-01-12 08:59:14 +00:00
|
|
|
# have we got any digits?
|
2011-01-17 19:09:35 +00:00
|
|
|
# If so, versenumber is everything from the digits to the end
|
2013-08-31 18:17:38 +00:00
|
|
|
match = re.match('(.*)(\d+.*)', marker)
|
2011-01-17 23:16:30 +00:00
|
|
|
if match:
|
|
|
|
marker = match.group(1).strip()
|
2011-01-17 16:21:46 +00:00
|
|
|
vn = match.group(2)
|
2013-08-31 18:17:38 +00:00
|
|
|
vt = MarkTypes.get(marker, 'O') if marker else 'V'
|
2014-03-06 20:40:08 +00:00
|
|
|
if regions_in_verses:
|
|
|
|
region = default_region
|
2011-01-17 16:21:46 +00:00
|
|
|
inst = 1
|
2014-03-06 20:40:08 +00:00
|
|
|
if self._list_has(verses, [reg, vt, vn, inst]):
|
2012-04-29 16:01:15 +00:00
|
|
|
inst = len(verses[reg][vt][vn]) + 1
|
2011-01-18 09:09:00 +00:00
|
|
|
else:
|
|
|
|
if not [reg, vt, vn, inst] in our_verse_order:
|
|
|
|
our_verse_order.append([reg, vt, vn, inst])
|
2012-04-29 15:31:56 +00:00
|
|
|
verses[reg].setdefault(vt, {})
|
|
|
|
verses[reg][vt].setdefault(vn, {})
|
|
|
|
verses[reg][vt][vn].setdefault(inst, [])
|
2014-03-05 18:58:22 +00:00
|
|
|
verses[reg][vt][vn][inst].append(self.tidy_text(line))
|
2011-01-12 08:59:14 +00:00
|
|
|
# done parsing
|
2011-01-17 16:21:46 +00:00
|
|
|
versetags = []
|
2011-01-12 15:10:20 +00:00
|
|
|
# we use our_verse_order to ensure, we insert lyrics in the same order
|
|
|
|
# as these appeared originally in the file
|
2011-01-17 23:16:30 +00:00
|
|
|
for [reg, vt, vn, inst] in our_verse_order:
|
2014-03-06 20:40:08 +00:00
|
|
|
if self._list_has(verses, [reg, vt, vn, inst]):
|
2011-02-15 21:19:45 +00:00
|
|
|
# this is false, but needs user input
|
2013-08-31 18:17:38 +00:00
|
|
|
versetag = '%s%s' % (vt, vn)
|
2011-01-17 23:16:30 +00:00
|
|
|
versetags.append(versetag)
|
2013-08-31 18:17:38 +00:00
|
|
|
lines = '\n'.join(verses[reg][vt][vn][inst])
|
2016-01-08 21:42:36 +00:00
|
|
|
self.add_verse(lines, versetag)
|
2011-01-17 16:21:46 +00:00
|
|
|
SeqTypes = {
|
2013-08-31 18:17:38 +00:00
|
|
|
'p': 'P1',
|
|
|
|
'q': 'P2',
|
|
|
|
'c': 'C1',
|
|
|
|
't': 'C2',
|
|
|
|
'b': 'B1',
|
|
|
|
'w': 'B2',
|
|
|
|
'e': 'E1'}
|
2011-01-17 19:09:35 +00:00
|
|
|
# Make use of Sequence data, determining the order of verses
|
2011-01-17 20:47:46 +00:00
|
|
|
try:
|
2013-08-31 18:17:38 +00:00
|
|
|
order = str(song.Sequence).strip().split(',')
|
2011-01-12 08:59:14 +00:00
|
|
|
for tag in order:
|
2012-04-29 15:31:56 +00:00
|
|
|
if not tag:
|
2011-01-17 22:27:25 +00:00
|
|
|
continue
|
|
|
|
elif tag[0].isdigit():
|
2013-08-31 18:17:38 +00:00
|
|
|
tag = 'V' + tag
|
2012-04-29 15:31:56 +00:00
|
|
|
elif tag.lower() in SeqTypes:
|
2011-01-17 16:21:46 +00:00
|
|
|
tag = SeqTypes[tag.lower()]
|
|
|
|
else:
|
2011-01-17 19:09:35 +00:00
|
|
|
continue
|
2011-01-17 23:16:30 +00:00
|
|
|
if tag in versetags:
|
2014-03-05 18:58:22 +00:00
|
|
|
self.verse_order_list.append(tag)
|
2011-01-17 23:16:30 +00:00
|
|
|
else:
|
2014-03-06 20:40:08 +00:00
|
|
|
log.info('Got order item %s, which is not in versetags, dropping item from presentation order', tag)
|
2011-01-17 22:27:25 +00:00
|
|
|
except UnicodeDecodeError:
|
2013-08-31 18:17:38 +00:00
|
|
|
log.exception('Unicode decode error while decoding Sequence')
|
2011-01-17 23:16:30 +00:00
|
|
|
self._success = False
|
2011-01-17 22:27:25 +00:00
|
|
|
except AttributeError:
|
2011-01-17 20:47:46 +00:00
|
|
|
pass
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
def _list_has(self, lst, sub_items):
|
|
|
|
"""
|
|
|
|
See if the list has sub items
|
|
|
|
|
|
|
|
:param lst: The list to check
|
|
|
|
:param sub_items: sub item list
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
for sub_item in sub_items:
|
|
|
|
if sub_item in lst:
|
|
|
|
lst = lst[sub_item]
|
2011-01-17 20:47:46 +00:00
|
|
|
else:
|
|
|
|
return False
|
|
|
|
return True
|
2011-01-18 09:09:00 +00:00
|
|
|
|
2014-03-06 20:40:08 +00:00
|
|
|
def _extract_region(self, line):
|
2014-05-02 06:42:17 +00:00
|
|
|
# this was true already: line[0:7] == '[region':
|
2014-03-06 20:40:08 +00:00
|
|
|
"""
|
|
|
|
Extract the region from text
|
|
|
|
|
|
|
|
:param line: The line of text
|
|
|
|
:return:
|
|
|
|
"""
|
2013-08-31 18:17:38 +00:00
|
|
|
right_bracket = line.find(']')
|
2011-01-17 20:47:46 +00:00
|
|
|
return line[7:right_bracket].strip()
|