openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #16413
[Merge] lp:~j-corwin/openlp/bug-1015823 into lp:openlp
Jonathan Corwin has proposed merging lp:~j-corwin/openlp/bug-1015823 into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~j-corwin/openlp/bug-1015823/+merge/113303
This adds an import for the SongPro text file export format.
It is based on Martin Barrett's example attached to http://support.openlp.org/issues/569, although somewhat rewritten.
I'm sharing the strip_rtf function from the ewimport, which will clash with mahfiaz's merge and his new and improved strip rtf function, but I got bored waiting!
--
https://code.launchpad.net/~j-corwin/openlp/bug-1015823/+merge/113303
Your team OpenLP Core is requested to review the proposed merge of lp:~j-corwin/openlp/bug-1015823 into lp:openlp.
=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py 2012-06-22 14:14:53 +0000
+++ openlp/plugins/songs/lib/__init__.py 2012-07-03 21:29:27 +0000
@@ -36,6 +36,7 @@
WHITESPACE = re.compile(r'[\W_]+', re.UNICODE)
APOSTROPHE = re.compile(u'[\'`’ʻ′]', re.UNICODE)
+RTF_STRIPPING_REGEX = re.compile(r'\{\\tx[^}]*\}')
class VerseType(object):
"""
@@ -366,6 +367,101 @@
if song.copyright:
song.copyright = CONTROL_CHARS.sub(u'', song.copyright).strip()
+def strip_rtf(blob, encoding):
+ depth = 0
+ control = False
+ clear_text = []
+ control_word = []
+
+ # workaround for \tx bug: remove one pair of curly braces
+ # if \tx is encountered
+ match = RTF_STRIPPING_REGEX.search(blob)
+ if match:
+ # start and end indices of match are curly braces - filter them out
+ blob = ''.join([blob[i] for i in xrange(len(blob))
+ if i != match.start() and i !=match.end()])
+ for c in blob:
+ if control:
+ # for delimiters, set control to False
+ if c == '{':
+ if control_word:
+ depth += 1
+ control = False
+ elif c == '}':
+ if control_word:
+ depth -= 1
+ control = False
+ elif c == '\\':
+ new_control = bool(control_word)
+ control = False
+ elif c.isspace():
+ control = False
+ else:
+ control_word.append(c)
+ if len(control_word) == 3 and control_word[0] == '\'':
+ control = False
+ if not control:
+ if not control_word:
+ if c == '{' or c == '}' or c == '\\':
+ clear_text.append(c)
+ else:
+ control_str = ''.join(control_word)
+ if control_str == 'par' or control_str == 'line':
+ clear_text.append(u'\n')
+ elif control_str == 'tab':
+ clear_text.append(u'\t')
+ # Prefer the encoding specified by the RTF data to that
+ # specified by the Paradox table header
+ # West European encoding
+ elif control_str == 'fcharset0':
+ encoding = u'cp1252'
+ # Greek encoding
+ elif control_str == 'fcharset161':
+ encoding = u'cp1253'
+ # Turkish encoding
+ elif control_str == 'fcharset162':
+ encoding = u'cp1254'
+ # Vietnamese encoding
+ elif control_str == 'fcharset163':
+ encoding = u'cp1258'
+ # Hebrew encoding
+ elif control_str == 'fcharset177':
+ encoding = u'cp1255'
+ # Arabic encoding
+ elif control_str == 'fcharset178':
+ encoding = u'cp1256'
+ # Baltic encoding
+ elif control_str == 'fcharset186':
+ encoding = u'cp1257'
+ # Cyrillic encoding
+ elif control_str == 'fcharset204':
+ encoding = u'cp1251'
+ # Thai encoding
+ elif control_str == 'fcharset222':
+ encoding = u'cp874'
+ # Central+East European encoding
+ elif control_str == 'fcharset238':
+ encoding = u'cp1250'
+ elif control_str[0] == '\'':
+ s = chr(int(control_str[1:3], 16))
+ clear_text.append(s.decode(encoding))
+ del control_word[:]
+ if c == '\\' and new_control:
+ control = True
+ elif c == '{':
+ depth += 1
+ elif c == '}':
+ depth -= 1
+ elif depth > 2:
+ continue
+ elif c == '\n' or c == '\r':
+ continue
+ elif c == '\\':
+ control = True
+ else:
+ clear_text.append(c)
+ return u''.join(clear_text)
+
from xml import OpenLyrics, SongXML
from songstab import SongsTab
from mediaitem import SongMediaItem
=== modified file 'openlp/plugins/songs/lib/ewimport.py'
--- openlp/plugins/songs/lib/ewimport.py 2012-06-22 14:14:53 +0000
+++ openlp/plugins/songs/lib/ewimport.py 2012-07-03 21:29:27 +0000
@@ -36,110 +36,14 @@
from openlp.core.lib import translate
from openlp.plugins.songs.lib import VerseType
-from openlp.plugins.songs.lib import retrieve_windows_encoding
+from openlp.plugins.songs.lib import retrieve_windows_encoding, strip_rtf
from songimport import SongImport
-RTF_STRIPPING_REGEX = re.compile(r'\{\\tx[^}]*\}')
# regex: at least two newlines, can have spaces between them
SLIDE_BREAK_REGEX = re.compile(r'\n *?\n[\n ]*')
NUMBER_REGEX = re.compile(r'[0-9]+')
NOTE_REGEX = re.compile(r'\(.*?\)')
-def strip_rtf(blob, encoding):
- depth = 0
- control = False
- clear_text = []
- control_word = []
-
- # workaround for \tx bug: remove one pair of curly braces
- # if \tx is encountered
- match = RTF_STRIPPING_REGEX.search(blob)
- if match:
- # start and end indices of match are curly braces - filter them out
- blob = ''.join([blob[i] for i in xrange(len(blob))
- if i != match.start() and i !=match.end()])
-
- for c in blob:
- if control:
- # for delimiters, set control to False
- if c == '{':
- if control_word:
- depth += 1
- control = False
- elif c == '}':
- if control_word:
- depth -= 1
- control = False
- elif c == '\\':
- new_control = bool(control_word)
- control = False
- elif c.isspace():
- control = False
- else:
- control_word.append(c)
- if len(control_word) == 3 and control_word[0] == '\'':
- control = False
- if not control:
- if not control_word:
- if c == '{' or c == '}' or c == '\\':
- clear_text.append(c)
- else:
- control_str = ''.join(control_word)
- if control_str == 'par' or control_str == 'line':
- clear_text.append(u'\n')
- elif control_str == 'tab':
- clear_text.append(u'\t')
- # Prefer the encoding specified by the RTF data to that
- # specified by the Paradox table header
- # West European encoding
- elif control_str == 'fcharset0':
- encoding = u'cp1252'
- # Greek encoding
- elif control_str == 'fcharset161':
- encoding = u'cp1253'
- # Turkish encoding
- elif control_str == 'fcharset162':
- encoding = u'cp1254'
- # Vietnamese encoding
- elif control_str == 'fcharset163':
- encoding = u'cp1258'
- # Hebrew encoding
- elif control_str == 'fcharset177':
- encoding = u'cp1255'
- # Arabic encoding
- elif control_str == 'fcharset178':
- encoding = u'cp1256'
- # Baltic encoding
- elif control_str == 'fcharset186':
- encoding = u'cp1257'
- # Cyrillic encoding
- elif control_str == 'fcharset204':
- encoding = u'cp1251'
- # Thai encoding
- elif control_str == 'fcharset222':
- encoding = u'cp874'
- # Central+East European encoding
- elif control_str == 'fcharset238':
- encoding = u'cp1250'
- elif control_str[0] == '\'':
- s = chr(int(control_str[1:3], 16))
- clear_text.append(s.decode(encoding))
- del control_word[:]
- if c == '\\' and new_control:
- control = True
- elif c == '{':
- depth += 1
- elif c == '}':
- depth -= 1
- elif depth > 2:
- continue
- elif c == '\n' or c == '\r':
- continue
- elif c == '\\':
- control = True
- else:
- clear_text.append(c)
- return u''.join(clear_text)
class FieldDescEntry:
def __init__(self, name, type, size):
=== modified file 'openlp/plugins/songs/lib/importer.py'
--- openlp/plugins/songs/lib/importer.py 2012-06-22 14:14:53 +0000
+++ openlp/plugins/songs/lib/importer.py 2012-07-03 21:29:27 +0000
@@ -44,6 +44,7 @@
from ewimport import EasyWorshipSongImport
from songbeamerimport import SongBeamerImport
from songshowplusimport import SongShowPlusImport
+from songproimport import SongProImport
from foilpresenterimport import FoilPresenterImport
from zionworximport import ZionWorxImport
# Imports that might fail
@@ -143,11 +144,11 @@
OpenSong = 9
PowerSong = 10
SongBeamer = 11
- SongShowPlus = 12
- SongsOfFellowship = 13
- WordsOfWorship = 14
- ZionWorx = 15
- #CSV = 16
+ SongPro = 12
+ SongShowPlus = 13
+ SongsOfFellowship = 14
+ WordsOfWorship = 15
+ ZionWorx = 16
# Set optional attribute defaults
__defaults__ = {
@@ -258,6 +259,18 @@
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',
@@ -293,12 +306,6 @@
'First convert your ZionWorx database to a CSV text file, as '
'explained in the <a href="http://manual.openlp.org/songs.html'
'#importing-from-zionworx">User Manual</a>.')
-# },
-# CSV: {
-# u'class': CSVImport,
-# u'name': WizardStrings.CSV,
-# u'prefix': u'csv',
-# u'selectMode': SongFormatSelect.SingleFile
}
}
@@ -320,6 +327,7 @@
SongFormat.OpenSong,
SongFormat.PowerSong,
SongFormat.SongBeamer,
+ SongFormat.SongPro,
SongFormat.SongShowPlus,
SongFormat.SongsOfFellowship,
SongFormat.WordsOfWorship,
=== added file 'openlp/plugins/songs/lib/songproimport.py'
--- openlp/plugins/songs/lib/songproimport.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/songproimport.py 2012-07-03 21:29:27 +0000
@@ -0,0 +1,145 @@
+# -*- 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, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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
+import logging
+
+from openlp.core.lib import translate
+from openlp.plugins.songs.lib import strip_rtf
+from openlp.plugins.songs.lib.songimport import SongImport
+
+log = logging.getLogger(__name__)
+
+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.
+ """
+ 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
+ self.importWizard.incrementProgressBar(u'Processing song ' + text,
+ 0)
+ return
+ elif tag == u'E':
+ self.finish()
+ return
+ if u'rtf1' in text:
+ text = strip_rtf(text, u'cp1252').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:])
Follow ups