Easislides import plugin

bzr-revno: 1226
This commit is contained in:
2011-01-18 17:26:57 +00:00 committed by Tim Bentley
commit f37e2707ef
4 changed files with 389 additions and 5 deletions

View File

@ -128,6 +128,9 @@ class SongImportForm(OpenLPWizard):
QtCore.QObject.connect(self.genericRemoveButton, QtCore.QObject.connect(self.genericRemoveButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onGenericRemoveButtonClicked) self.onGenericRemoveButtonClicked)
QtCore.QObject.connect(self.easiSlidesBrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onEasiSlidesBrowseButtonClicked)
QtCore.QObject.connect(self.ewBrowseButton, QtCore.QObject.connect(self.ewBrowseButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onEWBrowseButtonClicked) self.onEWBrowseButtonClicked)
@ -177,6 +180,8 @@ class SongImportForm(OpenLPWizard):
self.addMultiFileSelectItem(u'songsOfFellowship', None, True) self.addMultiFileSelectItem(u'songsOfFellowship', None, True)
# Generic Document/Presentation import # Generic Document/Presentation import
self.addMultiFileSelectItem(u'generic', None, True) self.addMultiFileSelectItem(u'generic', None, True)
# EasySlides
self.addSingleFileSelectItem(u'easiSlides')
# EasyWorship # EasyWorship
self.addSingleFileSelectItem(u'ew') self.addSingleFileSelectItem(u'ew')
# Words of Worship # Words of Worship
@ -226,10 +231,12 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', translate('SongsPlugin.ImportWizardForm',
'Generic Document/Presentation')) 'Generic Document/Presentation'))
self.formatComboBox.setItemText(8, self.formatComboBox.setItemText(8,
translate('SongsPlugin.ImportWizardForm', 'EasyWorship')) translate('SongsPlugin.ImportWizardForm', 'EasiSlides'))
self.formatComboBox.setItemText(9, self.formatComboBox.setItemText(9,
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
self.formatComboBox.setItemText(10,
translate('SongsPlugin.ImportWizardForm', 'SongBeamer')) translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
# self.formatComboBox.setItemText(9, # self.formatComboBox.setItemText(11,
# translate('SongsPlugin.ImportWizardForm', 'CSV')) # translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.openLP2FilenameLabel.setText( self.openLP2FilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:')) translate('SongsPlugin.ImportWizardForm', 'Filename:'))
@ -281,6 +288,10 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', 'The generic document/' translate('SongsPlugin.ImportWizardForm', 'The generic document/'
'presentation importer has been disabled because OpenLP cannot ' 'presentation importer has been disabled because OpenLP cannot '
'find OpenOffice.org on your computer.')) 'find OpenOffice.org on your computer.'))
self.easiSlidesFilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.easiSlidesBrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.ewFilenameLabel.setText( self.ewFilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:')) translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.ewBrowseButton.setText( self.ewBrowseButton.setText(
@ -311,6 +322,8 @@ class SongImportForm(OpenLPWizard):
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.openLP1FormLabelSpacer.changeSize(width, 0, self.openLP1FormLabelSpacer.changeSize(width, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.easiSlidesFormLabelSpacer.changeSize(width, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.ewFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed, self.ewFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed) QtGui.QSizePolicy.Fixed)
# self.csvFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed, # self.csvFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
@ -404,6 +417,16 @@ class SongImportForm(OpenLPWizard):
'presentation file to import from.')) 'presentation file to import from.'))
self.genericAddButton.setFocus() self.genericAddButton.setFocus()
return False return False
elif source_format == SongFormat.EasiSlides:
if self.easiSlidesFilenameEdit.text().isEmpty():
criticalErrorMessageBox(
translate('SongsPlugin.ImportWizardForm',
'No Easislides Songs file selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an xml song file exported from '
'EasiSlides, to import from.'))
self.easiSlidesBrowseButton.setFocus()
return False
elif source_format == SongFormat.EasyWorship: elif source_format == SongFormat.EasyWorship:
if self.ewFilenameEdit.text().isEmpty(): if self.ewFilenameEdit.text().isEmpty():
criticalErrorMessageBox( criticalErrorMessageBox(
@ -625,6 +648,13 @@ class SongImportForm(OpenLPWizard):
""" """
self.removeSelectedItems(self.genericFileListWidget) self.removeSelectedItems(self.genericFileListWidget)
def onEasiSlidesBrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select EasiSlides songfile'),
self.easiSlidesFilenameEdit
)
def onEWBrowseButtonClicked(self): def onEWBrowseButtonClicked(self):
""" """
Get EasyWorship song database files Get EasyWorship song database files
@ -674,6 +704,7 @@ class SongImportForm(OpenLPWizard):
self.ccliFileListWidget.clear() self.ccliFileListWidget.clear()
self.songsOfFellowshipFileListWidget.clear() self.songsOfFellowshipFileListWidget.clear()
self.genericFileListWidget.clear() self.genericFileListWidget.clear()
self.easiSlidesFilenameEdit.setText(u'')
self.ewFilenameEdit.setText(u'') self.ewFilenameEdit.setText(u'')
self.songBeamerFileListWidget.clear() self.songBeamerFileListWidget.clear()
#self.csvFilenameEdit.setText(u'') #self.csvFilenameEdit.setText(u'')
@ -737,8 +768,13 @@ class SongImportForm(OpenLPWizard):
importer = self.plugin.importSongs(SongFormat.Generic, importer = self.plugin.importSongs(SongFormat.Generic,
filenames=self.getListOfFiles(self.genericFileListWidget) filenames=self.getListOfFiles(self.genericFileListWidget)
) )
elif source_format == SongFormat.EasiSlides:
# Import an EasiSlides export file
importer = self.plugin.importSongs(SongFormat.EasiSlides,
filename=unicode(self.easiSlidesFilenameEdit.text())
)
elif source_format == SongFormat.EasyWorship: elif source_format == SongFormat.EasyWorship:
# Import an OpenLP 2.0 database # Import an EasyWorship database
importer = self.plugin.importSongs(SongFormat.EasyWorship, importer = self.plugin.importSongs(SongFormat.EasyWorship,
filename=unicode(self.ewFilenameEdit.text()) filename=unicode(self.ewFilenameEdit.text())
) )

View File

@ -0,0 +1,341 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 os
from lxml import etree, objectify
from lxml.etree import Error, LxmlError
import re
from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__)
class EasiSlidesImport(SongImport):
"""
Import songs exported from EasiSlides
The format example is here:
http://wiki.openlp.org/Development:EasiSlides_-_Song_Data_Format
"""
def __init__(self, manager, **kwargs):
"""
Initialise the class.
"""
SongImport.__init__(self, manager)
self.filename = kwargs[u'filename']
self.song = None
self.commit = True
def do_import(self):
"""
Import either each of the files in self.filenames - each element of
which can be either a single opensong file, or a zipfile containing
multiple opensong files. If `self.commit` is set False, the
import will not be committed to the database (useful for test scripts).
"""
self.import_wizard.progressBar.setMaximum(1)
log.info(u'Importing EasiSlides XML file %s', self.filename)
parser = etree.XMLParser(remove_blank_text=True)
file = etree.parse(self.filename, parser)
xml = unicode(etree.tostring(file))
song_xml = objectify.fromstring(xml)
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
u'Importing %s...')) % os.path.split(self.filename)[-1])
self.import_wizard.progressBar.setMaximum(len(song_xml.Item))
for song in song_xml.Item:
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
u'Importing %s, song %s...')) %
(os.path.split(self.filename)[-1], song.Title1))
success = self._parse_song(song)
if not success or self.stop_import_flag:
return False
elif self.commit:
self.finish()
return True
def _parse_song(self, song):
self._success = True
self._add_title(song)
self._add_alttitle(song)
self._add_number(song)
self._add_authors(song)
self._add_copyright(song)
self._add_book(song)
self._parse_and_add_lyrics(song)
return self._success
def _add_title(self, song):
try:
self.title = unicode(song.Title1).strip()
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Title1')
self._success = False
except AttributeError:
log.exception(u'no Title1')
self._success = False
def _add_alttitle(self, song):
try:
self.alternate_title = unicode(song.Title2).strip()
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Title2')
self._success = False
except AttributeError:
pass
def _add_number(self, song):
try:
number = unicode(song.SongNumber)
if number != u'0':
self.song_number = number
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding SongNumber')
self._success = False
except AttributeError:
pass
def _add_authors(self, song):
try:
authors = unicode(song.Writer).split(u',')
for author in authors:
author = author.strip()
if len(author) > 0:
self.authors.append(author)
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Writer')
self._success = False
except AttributeError:
pass
def _add_copyright(self, song):
copyright = []
try:
copyright.append(unicode(song.Copyright).strip())
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Copyright')
self._success = False
except AttributeError:
pass
try:
copyright.append(unicode(song.LicenceAdmin1).strip())
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding LicenceAdmin1')
self._success = False
except AttributeError:
pass
try:
copyright.append(unicode(song.LicenceAdmin2).strip())
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding LicenceAdmin2')
self._success = False
except AttributeError:
pass
self.add_copyright(u' '.join(copyright))
def _add_book(self, song):
try:
self.song_book_name = unicode(song.BookReference).strip()
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding BookReference')
self._success = False
except AttributeError:
pass
def _parse_and_add_lyrics(self, song):
try:
lyrics = unicode(song.Contents).strip()
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Contents')
self._success = False
except AttributeError:
log.exception(u'no Contents')
self._success = False
lines = lyrics.split(u'\n')
# we go over all lines first, to determine information,
# which tells us how to parse verses later
regionlines = {}
separatorlines = 0
for line in lines:
line = line.strip()
if len(line) == 0:
continue
elif line[1:7] == u'region':
# this is region separator, probably [region 2]
region = self._extractRegion(line)
if regionlines.has_key(region):
regionlines[region] = regionlines[region] + 1
else:
regionlines[region] = 1
elif line[0] == u'[':
separatorlines = separatorlines + 1
# if the song has separators
separators = (separatorlines > 0)
# the number of different regions in song - 1
if len(regionlines) > 1:
log.info(u'EasiSlidesImport: the file contained a song named "%s"'
u'with more than two regions, but only two regions are',
u'tested, encountered regions were: %s',
self.title, u','.join(regionlines.keys()))
# if the song has regions
regions = (len(regionlines) > 0)
# if the regions are inside verses
regionsInVerses = (regions and regionlines[regionlines.keys()[0]] > 1)
MarkTypes = {
u'CHORUS': u'C',
u'VERSE': u'V',
u'INTRO': u'I',
u'ENDING': u'E',
u'BRIDGE': u'B',
u'PRECHORUS': u'P'}
verses = {}
# list as [region, versetype, versenum, instance]
our_verse_order = []
defaultregion = u'1'
reg = defaultregion
verses[reg] = {}
# instance differentiates occurrences of same verse tag
vt = u'V'
vn = u'1'
inst = 1
for line in lines:
line = line.strip()
if len(line) == 0:
if separators:
# separators are used, so empty line means slide break
# inside verse
if self._listHas(verses, [reg, vt, vn, inst]):
inst = inst + 1
else:
# separators are not used, so empty line starts a new verse
vt = u'V'
if verses[reg].has_key(vt):
vn = len(verses[reg][vt].keys())+1
else:
vn = u'1'
inst = 1
elif line[0:7] == u'[region':
reg = self._extractRegion(line)
if not verses.has_key(reg):
verses[reg] = {}
if not regionsInVerses:
vt = u'V'
vn = u'1'
inst = 1
elif line[0] == u'[':
# this is a normal section marker
marker = line[1:line.find(u']')].upper()
vn = u'1'
# have we got any digits?
# If so, versenumber is everything from the digits to the end
match = re.match(u'(.*)(\d+.*)', marker)
if match:
marker = match.group(1).strip()
vn = match.group(2)
if len(marker) == 0:
vt = u'V'
elif MarkTypes.has_key(marker):
vt = MarkTypes[marker]
else:
vt = u'O'
if regionsInVerses:
region = defaultregion
inst = 1
if self._listHas(verses, [reg, vt, vn, inst]):
inst = len(verses[reg][vt][vn])+1
else:
if not [reg, vt, vn, inst] in our_verse_order:
our_verse_order.append([reg, vt, vn, inst])
if not verses[reg].has_key(vt):
verses[reg][vt] = {}
if not verses[reg][vt].has_key(vn):
verses[reg][vt][vn] = {}
if not verses[reg][vt][vn].has_key(inst):
verses[reg][vt][vn][inst] = []
words = self.tidy_text(line)
verses[reg][vt][vn][inst].append(words)
# done parsing
versetags = []
# we use our_verse_order to ensure, we insert lyrics in the same order
# as these appeared originally in the file
for [reg, vt, vn, inst] in our_verse_order:
if self._listHas(verses, [reg, vt, vn, inst]):
versetag = u'%s%s' % (vt, vn)
versetags.append(versetag)
lines = u'\n'.join(verses[reg][vt][vn][inst])
self.verses.append([versetag, lines])
SeqTypes = {
u'p': u'P1',
u'q': u'P2',
u'c': u'C1',
u't': u'C2',
u'b': u'B1',
u'w': u'B2',
u'e': u'E1'}
# Make use of Sequence data, determining the order of verses
try:
order = unicode(song.Sequence).strip().split(u',')
for tag in order:
if len(tag) == 0:
continue
elif tag[0].isdigit():
tag = u'V' + tag
elif SeqTypes.has_key(tag.lower()):
tag = SeqTypes[tag.lower()]
else:
continue
if tag in versetags:
self.verse_order_list.append(tag)
else:
log.info(u'Got order item %s, which is not in versetags,'
u'dropping item from presentation order', tag)
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Sequence')
self._success = False
except AttributeError:
pass
def _listHas(self, lst, subitems):
for i in subitems:
if type(lst) == type({}) and lst.has_key(i):
lst = lst[i]
elif type(lst) == type([]) and i in lst:
lst = lst[i]
else:
return False
return True
def _extractRegion(self, line):
# this was true already: line[0:7] == u'[region':
right_bracket = line.find(u']')
return line[7:right_bracket].strip()

View File

@ -27,6 +27,7 @@
The :mod:`importer` modules provides the general song import functionality. The :mod:`importer` modules provides the general song import functionality.
""" """
from opensongimport import OpenSongImport from opensongimport import OpenSongImport
from easislidesimport import EasiSlidesImport
from olpimport import OpenLPSongImport from olpimport import OpenLPSongImport
from openlyricsimport import OpenLyricsImport from openlyricsimport import OpenLyricsImport
from wowimport import WowImport from wowimport import WowImport
@ -67,8 +68,9 @@ class SongFormat(object):
SongsOfFellowship = 6 SongsOfFellowship = 6
Generic = 7 Generic = 7
#CSV = 8 #CSV = 8
EasyWorship = 8 EasiSlides = 8
SongBeamer = 9 EasyWorship = 9
SongBeamer = 10
@staticmethod @staticmethod
def get_class(format): def get_class(format):
@ -94,6 +96,8 @@ class SongFormat(object):
return OooImport return OooImport
elif format == SongFormat.CCLI: elif format == SongFormat.CCLI:
return CCLIFileImport return CCLIFileImport
elif format == SongFormat.EasiSlides:
return EasiSlidesImport
elif format == SongFormat.EasyWorship: elif format == SongFormat.EasyWorship:
return EasyWorshipSongImport return EasyWorshipSongImport
elif format == SongFormat.SongBeamer: elif format == SongFormat.SongBeamer:
@ -114,6 +118,7 @@ class SongFormat(object):
SongFormat.CCLI, SongFormat.CCLI,
SongFormat.SongsOfFellowship, SongFormat.SongsOfFellowship,
SongFormat.Generic, SongFormat.Generic,
SongFormat.EasiSlides,
SongFormat.EasyWorship, SongFormat.EasyWorship,
SongFormat.SongBeamer SongFormat.SongBeamer
] ]
@ -137,3 +142,4 @@ SongFormat.set_availability(SongFormat.SongsOfFellowship, HAS_SOF)
SongFormat.set_availability(SongFormat.Generic, HAS_OOO) SongFormat.set_availability(SongFormat.Generic, HAS_OOO)
__all__ = [u'SongFormat'] __all__ = [u'SongFormat']

View File

@ -258,6 +258,7 @@ class SongImport(QtCore.QObject):
log.info(u'commiting song %s to database', self.title) log.info(u'commiting song %s to database', self.title)
song = Song() song = Song()
song.title = self.title song.title = self.title
song.alternate_title = self.alternate_title
song.search_title = self.remove_punctuation(self.title).lower() \ song.search_title = self.remove_punctuation(self.title).lower() \
+ '@' + self.remove_punctuation(self.alternate_title).lower() + '@' + self.remove_punctuation(self.alternate_title).lower()
song.song_number = self.song_number song.song_number = self.song_number