diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index a51f3f2fc..d984d5a8d 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -476,7 +476,7 @@ def get_encoding(font, font_table, default_encoding, failed=False): Dictionary of fonts and respective encodings. ``default_encoding`` - The defaul encoding to use when font_table is empty or no font is used. + The default encoding to use when font_table is empty or no font is used. ``failed`` A boolean indicating whether the previous encoding didn't work. diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 2b04d6859..209539475 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -28,6 +28,7 @@ """ The :mod:`importer` modules provides the general song import functionality. """ +import os import logging from openlp.core.lib import translate @@ -44,6 +45,7 @@ from powersongimport import PowerSongImport from ewimport import EasyWorshipSongImport from songbeamerimport import SongBeamerImport from songshowplusimport import SongShowPlusImport +from songproimport import SongProImport from sundayplusimport import SundayPlusImport from foilpresenterimport import FoilPresenterImport from zionworximport import ZionWorxImport @@ -67,6 +69,13 @@ try: except ImportError: log.exception('Error importing %s', 'OooImport') HAS_OOO = False +HAS_MEDIASHOUT = False +if os.name == u'nt': + try: + from mediashoutimport import MediaShoutImport + HAS_MEDIASHOUT = True + except ImportError: + log.exception('Error importing %s', 'MediaShoutImport') class SongFormatSelect(object): @@ -141,15 +150,16 @@ class SongFormat(object): EasySlides = 6 EasyWorship = 7 FoilPresenter = 8 - OpenSong = 9 - PowerSong = 10 - SongBeamer = 11 - SongShowPlus = 12 - SongsOfFellowship = 13 - SundayPlus = 14 - WordsOfWorship = 15 - ZionWorx = 16 - #CSV = 17 + MediaShout = 9 + OpenSong = 10 + PowerSong = 11 + SongBeamer = 12 + SongPro = 13 + SongShowPlus = 14 + SongsOfFellowship = 15 + SundayPlus = 16 + WordsOfWorship = 17 + ZionWorx = 18 # Set optional attribute defaults __defaults__ = { @@ -240,6 +250,14 @@ class SongFormat(object): u'filter': u'%s (*.foil)' % translate( 'SongsPlugin.ImportWizardForm', 'Foilpresenter Song Files') }, + MediaShout: { + u'name': u'MediaShout', + u'prefix': u'mediaShout', + u'canDisable': True, + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', + 'MediaShout Database') + }, OpenSong: { u'class': OpenSongImport, u'name': WizardStrings.OS, @@ -260,6 +278,18 @@ class SongFormat(object): u'filter': u'%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files') }, + SongPro: { + u'class': SongProImport, + u'name': u'SongPro', + u'prefix': u'songPro', + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', + 'SongPro Text Files'), + u'comboBoxText': translate('SongsPlugin.ImportWizardForm', + 'SongPro (Export File)'), + u'descriptionText': translate('SongsPlugin.ImportWizardForm', + 'In SongPro, export your songs using the File -> Export menu') + }, SongShowPlus: { u'class': SongShowPlusImport, u'name': u'SongShow Plus', @@ -302,12 +332,6 @@ class SongFormat(object): 'First convert your ZionWorx database to a CSV text file, as ' 'explained in the User Manual.') -# }, -# CSV: { -# u'class': CSVImport, -# u'name': WizardStrings.CSV, -# u'prefix': u'csv', -# u'selectMode': SongFormatSelect.SingleFile } } @@ -326,9 +350,11 @@ class SongFormat(object): SongFormat.EasySlides, SongFormat.EasyWorship, SongFormat.FoilPresenter, + SongFormat.MediaShout, SongFormat.OpenSong, SongFormat.PowerSong, SongFormat.SongBeamer, + SongFormat.SongPro, SongFormat.SongShowPlus, SongFormat.SongsOfFellowship, SongFormat.SundayPlus, @@ -383,5 +409,8 @@ if HAS_SOF: SongFormat.set(SongFormat.Generic, u'availability', HAS_OOO) if HAS_OOO: SongFormat.set(SongFormat.Generic, u'class', OooImport) +SongFormat.set(SongFormat.MediaShout, u'availability', HAS_MEDIASHOUT) +if HAS_MEDIASHOUT: + SongFormat.set(SongFormat.MediaShout, u'class', MediaShoutImport) __all__ = [u'SongFormat', u'SongFormatSelect'] diff --git a/openlp/plugins/songs/lib/mediashoutimport.py b/openlp/plugins/songs/lib/mediashoutimport.py new file mode 100644 index 000000000..f81b208ac --- /dev/null +++ b/openlp/plugins/songs/lib/mediashoutimport.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Edwin Lunando, Joshua Miller, Stevan Pettit, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon # +# Tibble, Dave Warnock, 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 # +############################################################################### +""" +The :mod:`mediashoutimport` module provides the functionality for importing +a MediaShout database into the OpenLP database. +""" +import re +import os +import pyodbc + +from openlp.core.lib import translate +from openlp.plugins.songs.lib.songimport import SongImport + +VERSE_TAGS = [u'V', u'C', u'B', u'O', u'P', u'I', u'E'] + +class MediaShoutImport(SongImport): + """ + The :class:`MediaShoutImport` class provides the ability to import the + MediaShout Access Database + """ + def __init__(self, manager, **kwargs): + """ + Initialise the MediaShout importer. + """ + SongImport.__init__(self, manager, **kwargs) + + def doImport(self): + """ + Receive a single file to import. + """ + try: + conn = pyodbc.connect(u'DRIVER={Microsoft Access Driver (*.mdb)};' + u'DBQ=%s;PWD=6NOZ4eHK7k' % self.importSource) + except: + # Unfortunately no specific exception type + self.logError(self.importSource, + translate('SongsPlugin.MediaShoutImport', + 'Unable to open the MediaShout database.')) + return + cursor = conn.cursor() + cursor.execute(u'SELECT Record, Title, Author, Copyright, ' + u'SongID, CCLI, Notes FROM Songs ORDER BY Title') + songs = cursor.fetchall() + self.importWizard.progressBar.setMaximum(len(songs)) + for song in songs: + if self.stopImportFlag: + break + cursor.execute(u'SELECT Type, Number, Text FROM Verses ' + u'WHERE Record = %s ORDER BY Type, Number' % song.Record) + verses = cursor.fetchall() + cursor.execute(u'SELECT Type, Number, POrder FROM PlayOrder ' + u'WHERE Record = %s ORDER BY POrder' % song.Record) + verse_order = cursor.fetchall() + cursor.execute(u'SELECT Name FROM Themes INNER JOIN SongThemes ' + u'ON SongThemes.ThemeId = Themes.ThemeId ' + u'WHERE SongThemes.Record = %s' % song.Record) + topics = cursor.fetchall() + cursor.execute(u'SELECT Name FROM Groups INNER JOIN SongGroups ' + u'ON SongGroups.GroupId = Groups.GroupId ' + u'WHERE SongGroups.Record = %s' % song.Record) + topics += cursor.fetchall() + self.processSong(song, verses, verse_order, topics) + + def processSong(self, song, verses, verse_order, topics): + """ + Create the song, i.e. title, verse etc. + """ + self.setDefaults() + self.title = song.Title + self.parseAuthor(song.Author) + self.addCopyright(song.Copyright) + self.comments = song.Notes + for topic in topics: + self.topics.append(topic.Name) + if u'-' in song.SongID: + self.songBookName, self.songNumber = song.SongID.split(u'-', 1) + else: + self.songBookName = song.SongID + for verse in verses: + tag = VERSE_TAGS[verse.Type] + unicode(verse.Number) \ + if verse.Type < len(VERSE_TAGS) else u'O' + self.addVerse(verse.Text, tag) + for order in verse_order: + if order.Type < len(VERSE_TAGS): + self.verseOrderList.append(VERSE_TAGS[order.Type] + + unicode(order.Number)) + self.finish() diff --git a/openlp/plugins/songs/lib/songproimport.py b/openlp/plugins/songs/lib/songproimport.py new file mode 100644 index 000000000..44bf0cb44 --- /dev/null +++ b/openlp/plugins/songs/lib/songproimport.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Edwin Lunando, Joshua Miller, Stevan Pettit, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon # +# Tibble, Dave Warnock, 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 # +############################################################################### +""" +The :mod:`songproimport` module provides the functionality for importing SongPro +songs into the OpenLP database. +""" +import re +import os + +from openlp.core.lib import translate +from openlp.plugins.songs.lib import strip_rtf +from openlp.plugins.songs.lib.songimport import SongImport + +class SongProImport(SongImport): + """ + The :class:`SongProImport` class provides the ability to import song files + from SongPro export files. + + **SongPro Song File Format:** + + SongPro has the option to export under its File menu + This produces files containing single or multiple songs + The file is text with lines tagged with # followed by an identifier. + This is documented here: http://creationsoftware.com/ImportIdentifiers.php + An example here: http://creationsoftware.com/ExampleImportingManySongs.txt + + #A - next line is the Song Author + #B - the lines following until next tagged line are the "Bridge" words + (can be in rtf or plain text) which we map as B1 + #C - the lines following until next tagged line are the chorus words + (can be in rtf or plain text) + which we map as C1 + #D - the lines following until next tagged line are the "Ending" words + (can be in rtf or plain text) which we map as E1 + #E - this song ends here, so we process the song - + and start again at the next line + #G - next line is the Group + #M - next line is the Song Number + #N - next line are Notes + #R - next line is the SongCopyright + #O - next line is the Verse Sequence + #T - next line is the Song Title + #1 - #7 the lines following until next tagged line are the verse x words + (can be in rtf or plain text) + """ + def __init__(self, manager, **kwargs): + """ + Initialise the SongPro importer. + """ + SongImport.__init__(self, manager, **kwargs) + + def doImport(self): + """ + Receive a single file or a list of files to import. + """ + self.encoding = None + with open(self.importSource, 'r') as songs_file: + self.importWizard.progressBar.setMaximum(0) + tag = u'' + text = u'' + for file_line in songs_file: + if self.stopImportFlag: + break + file_line = unicode(file_line, u'cp1252') + file_text = file_line.rstrip() + if file_text and file_text[0] == u'#': + self.processSection(tag, text.rstrip()) + tag = file_text[1:] + text = u'' + else: + text += file_line + + def processSection(self, tag, text): + """ + Process a section of the song, i.e. title, verse etc. + """ + if tag == u'T': + self.setDefaults() + if text: + self.title = text + return + elif tag == u'E': + self.finish() + return + if u'rtf1' in text: + text, self.encoding = strip_rtf(text, self.encoding) + text = text.rstrip() + if not text: + return + if tag == u'A': + self.parseAuthor(text) + elif tag in [u'B', u'C']: + self.addVerse(text, tag) + elif tag == u'D': + self.addVerse(text, u'E') + elif tag == u'G': + self.topics.append(text) + elif tag == u'M': + matches = re.findall(r'\d+', text) + if matches: + self.songNumber = matches[-1] + self.songBookName = text[:text.rfind(self.songNumber)] + elif tag == u'N': + self.comments = text + elif tag == u'O': + for char in text: + if char == u'C': + self.verseOrderList.append(u'C1') + elif char == u'B': + self.verseOrderList.append(u'B1') + elif char == u'D': + self.verseOrderList.append(u'E1') + elif u'1' <= char <= u'7': + self.verseOrderList.append(u'V' + char) + elif tag == u'R': + self.addCopyright(text) + elif u'1' <= tag <= u'7': + self.addVerse(text, u'V' + tag[1:])