openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #02478
[Merge] lp:~mjthompson/openlp/opensong_import into lp:openlp
Martin Thompson has proposed merging lp:~mjthompson/openlp/opensong_import into lp:openlp.
Requested reviews:
Jonathan Corwin (j-corwin)
Makes use of existing SOF import classes to import Opensong format files. Successfully imports all the Songs Of Fellowship files and all of the "default" set of opensong files.
Fixed a bunch of bugs spotted in the last attempt. CCLI no is now imported. Themes are not yet.
Temporary GUI option for import created, as with SOF import.
Still todo
- make it work on files with non-ASCII chars in.
- no doubt there still at least one = sign without spaces around it :) I've tried to find them all though!
- theme import
--
https://code.launchpad.net/~mjthompson/openlp/opensong_import/+merge/29927
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py 2010-07-04 16:40:53 +0000
+++ openlp/plugins/songs/lib/__init__.py 2010-07-14 20:55:54 +0000
@@ -137,10 +137,11 @@
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
-from xml import LyricsXML, SongXMLBuilder, SongXMLParser
+from lyrics_xml import LyricsXML, SongXMLBuilder, SongXMLParser
from songstab import SongsTab
from mediaitem import SongMediaItem
from songimport import SongImport
+from opensongimport import OpenSongImport
try:
from sofimport import SofImport
from oooimport import OooImport
=== renamed file 'openlp/plugins/songs/lib/xml.py' => 'openlp/plugins/songs/lib/lyrics_xml.py'
--- openlp/plugins/songs/lib/xml.py 2010-07-05 21:23:39 +0000
+++ openlp/plugins/songs/lib/lyrics_xml.py 2010-07-14 20:55:54 +0000
@@ -49,7 +49,7 @@
"""
log.info(u'SongXMLBuilder Loaded')
- def __init__(self, song_language=None):
+ def __init__(self, song_language = None):
"""
Set up the song builder.
@@ -76,8 +76,8 @@
``content``
The actual text of the verse to be stored.
"""
- #log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
- verse = etree.Element(u'verse', type=type, label=number)
+ # log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
+ verse = etree.Element(u'verse', type = unicode(type), label = unicode(number))
verse.text = etree.CDATA(content)
self.lyrics.append(verse)
@@ -85,14 +85,14 @@
"""
Debugging aid to dump XML so that we can see what we have.
"""
- return etree.tostring(self.song_xml, encoding=u'UTF-8',
+ return etree.tostring(self.song_xml, encoding = u'UTF-8',
xml_declaration=True, pretty_print=True)
def extract_xml(self):
"""
Extract our newly created XML song.
"""
- return etree.tostring(self.song_xml, encoding=u'UTF-8',
+ return etree.tostring(self.song_xml, encoding = u'UTF-8',
xml_declaration=True)
=== added file 'openlp/plugins/songs/lib/opensongimport.py'
--- openlp/plugins/songs/lib/opensongimport.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/opensongimport.py 2010-07-14 20:55:54 +0000
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
+# Thompson, Jon Tibble, Carsten Tinggaard #
+# --------------------------------------------------------------------------- #
+# 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 os
+import re
+
+from songimport import SongImport
+from lxml.etree import Element
+from lxml import objectify
+
+from zipfile import ZipFile
+
+import logging
+log = logging.getLogger(__name__)
+
+class OpenSongImportError(Exception):
+ pass
+
+class OpenSongImport:
+ """
+ Import songs exported from OpenSong - the format is described loosly here:
+ http://www.opensong.org/d/manual/song_file_format_specification
+
+ However, it doesn't describe the <lyrics> section, so here's an attempt:
+
+ Verses can be expressed in one of 2 ways:
+ <lyrics>
+ [v1]List of words
+ Another Line
+
+ [v2]Some words for the 2nd verse
+ etc...
+ </lyrics>
+
+ The 'v' can be left out - it is implied
+ or:
+ <lyrics>
+ [V]
+ 1List of words
+ 2Some words for the 2nd Verse
+
+ 1Another Line
+ 2etc...
+ </lyrics>
+
+ Either or both forms can be used in one song. The Number does not
+ necessarily appear at the start of the line
+
+ The [v1] labels can have either upper or lower case Vs
+ Other labels can be used also:
+ C - Chorus
+ B - Bridge
+
+ Guitar chords can be provided 'above' the lyrics (the line is
+ preceeded by a'.') and _s can be used to signify long-drawn-out
+ words:
+
+ . A7 Bm
+ 1 Some____ Words
+
+ Chords and _s are removed by this importer.
+
+ The verses etc. are imported and tagged appropriately.
+
+ The <presentation> tag is used to populate the OpenLP verse
+ display order field. The Author and Copyright tags are also
+ imported to the appropriate places.
+
+ """
+ def __init__(self, songmanager):
+ """
+ Initialise the class. Requires a songmanager class which
+ is passed to SongImport for writing song to disk
+ """
+ self.songmanager = songmanager
+ self.song = None
+
+ def do_import(self, filename, commit=True):
+ """
+ Import either a single opensong file, or a zipfile
+ containing multiple opensong files If the commit parameter is
+ set False, the import will not be committed to the database
+ (useful for test scripts)
+ """
+ ext=os.path.splitext(filename)[1]
+ if ext.lower() == ".zip":
+ log.info('Zipfile found %s', filename)
+ z=ZipFile(filename, u'r')
+ for song in z.infolist():
+ parts=os.path.split(song.filename)
+ if parts[-1] == u'':
+ #No final part => directory
+ continue
+ songfile = z.open(song)
+ self.do_import_file(songfile)
+ if commit:
+ self.finish()
+ else:
+ log.info('Direct import %s', filename)
+ file = open(filename)
+ self.do_import_file(file)
+ if commit:
+ self.finish()
+
+
+ def do_import_file(self, file):
+ """
+ Process the OpenSong file - pass in a file-like object,
+ not a filename
+ """
+ self.song = SongImport(self.songmanager)
+ tree = objectify.parse(file)
+ root = tree.getroot()
+ fields = dir(root)
+ decode = {u'copyright':self.song.add_copyright,
+ u'ccli':self.song.set_ccli_number,
+ u'author':self.song.parse_author,
+ u'title':self.song.set_title,
+ u'aka':self.song.set_alternate_title,
+ u'hymn_number':self.song.set_song_number}
+ for (attr, fn) in decode.items():
+ if attr in fields:
+ fn(unicode(root.__getattr__(attr)))
+
+ res = []
+ if u'theme' in fields:
+ res.append(unicode(root.theme))
+ if u'alttheme' in fields:
+ res.append(unicode(root.alttheme))
+ self.song.theme_name = u', '.join(res)
+
+ # data storage while importing
+ verses = {}
+ lyrics = unicode(root.lyrics)
+ # keep track of a "default" verse order, in case none is specified
+ our_verse_order = []
+ verses_seen = {}
+ # in the absence of any other indication, verses are the default,
+ # erm, versetype!
+ versetype = u'V'
+ for l in lyrics.split(u'\n'):
+ # remove comments
+ semicolon = l.find(u';')
+ if semicolon >= 0:
+ l = l[:semicolon]
+ l = l.strip()
+ if len(l) == 0:
+ continue
+ # skip inline guitar chords and page and column breaks
+ if l[0] == u'.' or l.startswith(u'---') or l.startswith(u'-!!'):
+ continue
+
+ # verse/chorus/etc. marker
+ if l[0] == u'[':
+ versetype = l[1].upper()
+ if versetype.isdigit():
+ versenum = versetype
+ versetype = u'V'
+ elif l[2] != u']':
+ # there's a number to go with it - extract that as well
+ right_bracket = l.find(u']')
+ versenum = l[2:right_bracket]
+ else:
+ # if there's no number, assume it's no.1
+ versenum = u'1'
+ continue
+ words = None
+
+ # number at start of line.. it's verse number
+ if l[0].isdigit():
+ versenum = l[0]
+ words = l[1:].strip()
+ if words is None and \
+ versenum is not None and \
+ versetype is not None:
+ words = l
+ if versenum is not None:
+ versetag = u'%s%s'%(versetype,versenum)
+ if not verses.has_key(versetype):
+ verses[versetype] = {}
+ if not verses[versetype].has_key(versenum):
+ verses[versetype][versenum] = [] # storage for lines in this verse
+ if not verses_seen.has_key(versetag):
+ verses_seen[versetag] = 1
+ our_verse_order.append(versetag)
+ if words:
+ # Tidy text and remove the ____s from extended words
+ # words=self.song.tidy_text(words)
+ words=words.replace('_', '')
+ verses[versetype][versenum].append(words)
+ # done parsing
+ versetypes = verses.keys()
+ versetypes.sort()
+ versetags = {}
+ verse_renames = {}
+ for v in versetypes:
+ versenums = verses[v].keys()
+ versenums.sort()
+ for n in versenums:
+ versetag = u'%s%s' %(v,n)
+ lines = u'\n'.join(verses[v][n])
+ self.song.verses.append([versetag, lines])
+ versetags[versetag] = 1 # keep track of what we have for error checking later
+ # now figure out the presentation order
+ if u'presentation' in fields and root.presentation != u'':
+ order = unicode(root.presentation)
+ order = order.split()
+ else:
+ assert len(our_verse_order)>0
+ order = our_verse_order
+ for tag in order:
+ if len(tag) == 1:
+ tag = tag + u'1' # Assume it's no.1 if it's not there
+ if not versetags.has_key(tag):
+ log.warn(u'Got order %s but not in versetags, skipping', tag)
+ else:
+ self.song.verse_order_list.append(tag)
+ def finish(self):
+ """ Separate function, allows test suite to not pollute database"""
+ self.song.finish()
=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py 2010-07-03 17:46:00 +0000
+++ openlp/plugins/songs/lib/songimport.py 2010-07-14 20:55:54 +0000
@@ -163,6 +163,12 @@
"""
self.song_number = song_number
+ def set_ccli_number(self, cclino):
+ """
+ Set the ccli number
+ """
+ self.ccli_number = cclino
+
def set_song_book(self, song_book, publisher):
"""
Set the song book name and publisher
@@ -267,7 +273,7 @@
def commit_song(self):
"""
- Write the song and it's fields to disk
+ Write the song and its fields to disk
"""
song = Song()
song.title = self.title
@@ -319,8 +325,7 @@
self.manager.save_object(song_book)
song.song_book_id = song_book.id
for topictext in self.topics:
- topic = self.manager.get_object_filtered(Topic,
- Topic.name == topictext)
+ topic = self.manager.get_object_filtered(Topic.name == topictext)
if topic is None:
topic = Topic()
topic.name = topictext
=== modified file 'openlp/plugins/songs/lib/songxml.py'
--- openlp/plugins/songs/lib/songxml.py 2010-07-03 13:26:29 +0000
+++ openlp/plugins/songs/lib/songxml.py 2010-07-14 20:55:54 +0000
@@ -60,175 +60,6 @@
# TODO: Song: Import ChangingSong
# TODO: Song: Export ChangingSong
-_BLANK_OPENSONG_XML = \
-'''<?xml version="1.0" encoding="UTF-8"?>
-<song>
- <title></title>
- <author></author>
- <copyright></copyright>
- <presentation></presentation>
- <ccli></ccli>
- <lyrics></lyrics>
- <theme></theme>
- <alttheme></alttheme>
-</song>
-'''
-
-class _OpenSong(object):
- """
- Class for import of OpenSong
- """
- def __init__(self, xmlContent = None):
- """
- Initialize from given xml content
- """
- self._set_from_xml(_BLANK_OPENSONG_XML, 'song')
- if xmlContent:
- self._set_from_xml(xmlContent, 'song')
-
- def _set_from_xml(self, xml, root_tag):
- """
- Set song properties from given xml content.
-
- ``xml``
- Formatted xml tags and values.
- ``root_tag``
- The root tag of the xml.
- """
- root = ElementTree(element=XML(xml))
- xml_iter = root.getiterator()
- for element in xml_iter:
- if element.tag != root_tag:
- text = element.text
- if text is None:
- val = text
- elif isinstance(text, basestring):
- # Strings need special handling to sort the colours out
- if text[0] == u'$':
- # This might be a hex number, let's try to convert it.
- try:
- val = int(text[1:], 16)
- except ValueError:
- pass
- else:
- # Let's just see if it's a integer.
- try:
- val = int(text)
- except ValueError:
- # Ok, it seems to be a string.
- val = text
- if hasattr(self, u'post_tag_hook'):
- (element.tag, val) = \
- self.post_tag_hook(element.tag, val)
- setattr(self, element.tag, val)
-
- def __str__(self):
- """
- Return string with all public attributes
-
- The string is formatted with one attribute per line
- If the string is split on newline then the length of the
- list is equal to the number of attributes
- """
- attributes = []
- for attrib in dir(self):
- if not attrib.startswith(u'_'):
- attributes.append(
- u'%30s : %s' % (attrib, getattr(self, attrib)))
- return u'\n'.join(attributes)
-
- def _get_as_string(self):
- """
- Return one string with all public attributes
- """
- result = u''
- for attrib in dir(self):
- if not attrib.startswith(u'_'):
- result += u'_%s_' % getattr(self, attrib)
- return result
-
- def get_author_list(self):
- """Convert author field to an authorlist
-
- in OpenSong an author list may be separated by '/'
- return as a string
- """
- if self.author:
- list = self.author.split(u' and ')
- res = [item.strip() for item in list]
- return u', '.join(res)
-
- def get_category_array(self):
- """Convert theme and alttheme into category_array
-
- return as a string
- """
- res = []
- if self.theme:
- res.append(self.theme)
- if self.alttheme:
- res.append(self.alttheme)
- return u', u'.join(res)
-
- def _reorder_verse(self, tag, tmpVerse):
- """
- Reorder the verse in case of first char is a number
- tag -- the tag of this verse / verse group
- tmpVerse -- list of strings
- """
- res = []
- for digit in '1234567890 ':
- tagPending = True
- for line in tmpVerse:
- if line.startswith(digit):
- if tagPending:
- tagPending = False
- tagChar = tag.strip(u'[]').lower()
- if 'v' == tagChar:
- newtag = "Verse"
- elif 'c' == tagChar:
- newtag = "Chorus"
- elif 'b' == tagChar:
- newtag = "Bridge"
- elif 'p' == tagChar:
- newtag = "Pre-chorus"
- else:
- newtag = tagChar
- tagString = (u'# %s %s' % (newtag, digit)).rstrip()
- res.append(tagString)
- res.append(line[1:])
- if (len(line) == 0) and (not tagPending):
- res.append(line)
- return res
-
- def get_lyrics(self):
- """
- Convert the lyrics to openlp lyrics format
- return as list of strings
- """
- lyrics = self.lyrics.split(u'\n')
- tmpVerse = []
- finalLyrics = []
- tag = ""
- for lyric in lyrics:
- line = lyric.rstrip()
- if not line.startswith(u'.'):
- # drop all chords
- tmpVerse.append(line)
- if line:
- if line.startswith(u'['):
- tag = line
- else:
- reorderedVerse = self._reorder_verse(tag, tmpVerse)
- finalLyrics.extend(reorderedVerse)
- tag = ""
- tmpVerse = []
- # catch up final verse
- reorderedVerse = self._reorder_verse(tag, tmpVerse)
- finalLyrics.extend(reorderedVerse)
- return finalLyrics
-
-
class Song(object):
"""Handling song properties and methods
@@ -275,7 +106,7 @@
show_author_list -- 0: no show, 1: show
show_copyright -- 0: no show, 1: show
show_song_cclino -- 0: no show, 1: show
- theme -- name of theme or blank
+ theme_name -- name of theme or blank
category_array -- list of user defined properties (hymn, gospel)
song_book -- name of originating book
song_number -- number of the song, related to a songbook
@@ -298,7 +129,7 @@
self.show_copyright = 1
self.show_song_cclino = 1
self.show_title = 1
- self.theme = ""
+ self.theme_name = ""
self.category_array = None
self.song_book = ""
self.song_number = ""
@@ -307,40 +138,6 @@
self.set_lyrics(u'')
return
- def from_opensong_buffer(self, xmlcontent):
- """Initialize from buffer(string) of xml lines in opensong format"""
- self._reset()
- opensong = _OpenSong(xmlcontent)
- if opensong.title:
- self.set_title(opensong.title)
- if opensong.copyright:
- self.set_copyright(opensong.copyright)
- if opensong.presentation:
- self.set_verse_order(opensong.presentation)
- if opensong.ccli:
- self.set_song_cclino(opensong.ccli)
- self.set_author_list(opensong.get_author_list())
- self.set_category_array(opensong.get_category_array())
- self.set_lyrics(opensong.get_lyrics())
-
- def from_opensong_file(self, xmlfilename):
- """
- Initialize from file containing xml
- xmlfilename -- path to xml file
- """
- osfile = None
- try:
- osfile = open(xmlfilename, 'r')
- list = [line for line in osfile]
- osfile.close()
- xml = "".join(list)
- self.from_opensong_buffer(xml)
- except IOError:
- log.exception(u'Failed to load opensong xml file')
- finally:
- if osfile:
- osfile.close()
-
def _remove_punctuation(self, title):
"""Remove the puntuation chars from title
@@ -424,7 +221,7 @@
self.set_title(sName)
self.set_author_list(author_list)
self.set_copyright(sCopyright)
- self.set_song_cclino(sCcli)
+ self.set_ccli_number(sCcli)
self.set_lyrics(lyrics)
def from_ccli_text_file(self, textFileName):
@@ -479,21 +276,21 @@
"""Set the copyright string"""
self.copyright = copyright
- def get_song_cclino(self):
+ def get_ccli_number(self):
"""Return the songCclino"""
- return self._assure_string(self.song_cclino)
-
- def set_song_cclino(self, song_cclino):
- """Set the song_cclino"""
- self.song_cclino = song_cclino
-
- def get_theme(self):
+ return self._assure_string(self.ccli_number)
+
+ def set_ccli_number(self, ccli_number):
+ """Set the ccli_number"""
+ self.ccli_number = ccli_number
+
+ def get_theme_name(self):
"""Return the theme name for the song"""
- return self._assure_string(self.theme)
+ return self._assure_string(self.theme_name)
- def set_theme(self, theme):
+ def set_theme_name(self, theme_name):
"""Set the theme name (string)"""
- self.theme = theme
+ self.theme_name = theme_name
def get_song_book(self):
"""Return the song_book (string)"""
@@ -532,9 +329,9 @@
asOneString
True -- string:
- "John Newton, A Parker"
+ 'John Newton, A Parker'
False -- list of strings
- ["John Newton", u'A Parker"]
+ ['John Newton', u'A Parker']
"""
if asOneString:
res = self._assure_string(self.author_list)
@@ -557,9 +354,9 @@
asOneString
True -- string:
- "Hymn, Gospel"
+ 'Hymn, Gospel'
False -- list of strings
- ["Hymn", u'Gospel"]
+ ['Hymn', u'Gospel']
"""
if asOneString:
res = self._assure_string(self.category_array)
@@ -601,13 +398,13 @@
"""Set the show_copyright flag (bool)"""
self.show_copyright = show_copyright
- def get_show_song_cclino(self):
+ def get_show_ccli_number(self):
"""Return the showSongCclino (string)"""
- return self.show_song_cclino
+ return self.show_ccli_number
- def set_show_song_cclino(self, show_song_cclino):
- """Set the show_song_cclino flag (bool)"""
- self.show_song_cclino = show_song_cclino
+ def set_show_ccli_number(self, show_ccli_number):
+ """Set the show_ccli_number flag (bool)"""
+ self.show_ccli_number = show_ccli_number
def get_lyrics(self):
"""Return the lyrics as a list of strings
@@ -674,7 +471,7 @@
slideNumber -- 1 .. numberOfSlides
Returns a list as:
- [theme (string),
+ [theme_name (string),
title (string),
authorlist (string),
copyright (string),
@@ -699,13 +496,13 @@
cpright = self.get_copyright()
else:
cpright = ""
- if self.show_song_cclino:
- ccli = self.get_song_cclino()
+ if self.show_ccli_number:
+ ccli = self.get_ccli_number()
else:
ccli = ""
- theme = self.get_theme()
+ theme_name = self.get_theme_name()
# examine the slide for a theme
- res.append(theme)
+ res.append(theme_name)
res.append(title)
res.append(author)
res.append(cpright)
=== added directory 'openlp/plugins/songs/lib/test'
=== added file 'openlp/plugins/songs/lib/test/test.opensong'
--- openlp/plugins/songs/lib/test/test.opensong 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/test/test.opensong 2010-07-14 20:55:54 +0000
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<song>
+ <title>Martins Test</title>
+ <author>Martià Thómpson</author>
+ <copyright>2010 Martin Thompson</copyright>
+ <hymn_number>1</hymn_number>
+ <presentation>V1 C V2 C2 V3 B1 V1</presentation>
+ <ccli>Blah</ccli>
+ <capo print="false"></capo>
+ <key></key>
+ <aka></aka>
+ <key_line></key_line>
+ <user1></user1>
+ <user2></user2>
+ <user3></user3>
+ <theme>TestTheme</theme>
+ <alttheme>TestAltTheme</alttheme>
+ <tempo></tempo>
+ <time_sig></time_sig>
+ <lyrics>;Comment
+. A B C
+1 v1 Line 1___
+2 v2 Line 1___
+. A B C7
+1 V1 Line 2
+2 V2 Line 2
+
+[3]
+ V3 Line 1
+ V3 Line 2
+
+[b1]
+ Bridge 1
+---
+-!!
+ Bridge 1 line 2
+
+[C]
+. A B
+ Chorus 1
+
+[C2]
+. A B
+ Chorus 2
+ </lyrics>
+ <style index="default_style">
+ <title enabled="true" valign="bottom" align="center" include_verse="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="26" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/>
+ <subtitle enabled="true" valign="bottom" align="center" descriptive="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="18" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/>
+ <song_subtitle>author</song_subtitle>
+ <body enabled="true" auto_scale="false" valign="middle" align="center" highlight_chorus="true" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="34" bold="true" italic="false" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#FF0000">
+ <tabs/>
+</body>
+ <background strip_footer="0" color="#408080" position="1"/>
+</style></song>
=== added file 'openlp/plugins/songs/lib/test/test.opensong.zip'
Binary files openlp/plugins/songs/lib/test/test.opensong.zip 1970-01-01 00:00:00 +0000 and openlp/plugins/songs/lib/test/test.opensong.zip 2010-07-14 20:55:54 +0000 differ
=== added file 'openlp/plugins/songs/lib/test/test2.opensong'
--- openlp/plugins/songs/lib/test/test2.opensong 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/test/test2.opensong 2010-07-14 20:55:54 +0000
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<song>
+ <title>Martins 2nd Test</title>
+ <author>Martin Thompson</author>
+ <copyright>2010 Martin Thompson</copyright>
+ <hymn_number>2</hymn_number>
+ <presentation></presentation>
+ <ccli>Blah</ccli>
+ <capo print="false"></capo>
+ <key></key>
+ <aka></aka>
+ <key_line></key_line>
+ <user1></user1>
+ <user2></user2>
+ <user3></user3>
+ <theme></theme>
+ <tempo></tempo>
+ <time_sig></time_sig>
+ <lyrics>;Comment
+[V]
+. A B C
+1 v1 Line 1___
+2 v2 Line 1___
+. A B C7
+1 V1 Line 2
+2 V2 Line 2
+
+[b1]
+ Bridge 1
+ Bridge 1 line 2
+[C1]
+ Chorus 1
+
+[C2]
+ Chorus 2
+ </lyrics>
+ <style index="default_style">
+ <title enabled="true" valign="bottom" align="center" include_verse="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="26" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/>
+ <subtitle enabled="true" valign="bottom" align="center" descriptive="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="18" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/>
+ <song_subtitle>author</song_subtitle>
+ <body enabled="true" auto_scale="false" valign="middle" align="center" highlight_chorus="true" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="34" bold="true" italic="false" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#FF0000">
+ <tabs/>
+</body>
+ <background strip_footer="0" color="#408080" position="1"/>
+</style></song>
=== added file 'openlp/plugins/songs/lib/test/test_importing_lots.py'
--- openlp/plugins/songs/lib/test/test_importing_lots.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/test/test_importing_lots.py 2010-07-14 20:55:54 +0000
@@ -0,0 +1,56 @@
+from openlp.plugins.songs.lib.opensongimport import OpenSongImport
+from openlp.plugins.songs.lib.db import init_schema
+from openlp.core.lib.db import Manager
+from glob import glob
+from zipfile import ZipFile
+import os
+from traceback import print_exc
+import sys
+import codecs
+def opensong_import_lots():
+ ziploc = u'/home/mjt/openlp/OpenSong_Data/'
+ files = []
+ #files = [u'test.opensong.zip', ziploc+u'ADond.zip']
+ files.extend(glob(ziploc+u'Songs.zip'))
+ #files.extend(glob(ziploc+u'SOF.zip'))
+ #files.extend(glob(ziploc+u'spanish_songs_for_opensong.zip'))
+# files.extend(glob(ziploc+u'opensong_*.zip'))
+ errfile = codecs.open(u'import_lots_errors.txt', u'w', u'utf8')
+ manager = Manager(u'songs', init_schema)
+ for file in files:
+ print u'Importing', file
+ z = ZipFile(file, u'r')
+ for song in z.infolist():
+ # need to handle unicode filenames (CP437 - Winzip does this)
+ filename = song.filename#.decode('cp852')
+ parts = os.path.split(filename)
+ if parts[-1] == u'':
+ #No final part => directory
+ continue
+ print " ", file, ":",filename,
+ songfile = z.open(song)
+ #z.extract(song)
+ #songfile=open(filename, u'r')
+ o = OpenSongImport(manager)
+ try:
+ o.do_import_file(songfile)
+ o.song.print_song()
+ except:
+ print "Failure",
+
+ errfile.write(u'Failure: %s:%s\n' %(file, filename.decode('cp437')))
+ songfile = z.open(song)
+ for l in songfile.readlines():
+ l = l.decode('utf8')
+ print(u' |%s\n' % l.strip())
+ errfile.write(u' |%s\n'%l.strip())
+ print_exc(3, file = errfile)
+ print_exc(3)
+ sys.exit(1)
+ # continue
+ #o.finish()
+ print "OK"
+ #os.unlink(filename)
+ # o.song.print_song()
+if __name__ == "__main__":
+ opensong_import_lots()
=== added file 'openlp/plugins/songs/lib/test/test_opensongimport.py'
--- openlp/plugins/songs/lib/test/test_opensongimport.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/test/test_opensongimport.py 2010-07-14 20:55:54 +0000
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
+# Thompson, Jon Tibble, Carsten Tinggaard #
+# --------------------------------------------------------------------------- #
+# 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 #
+###############################################################################
+from openlp.plugins.songs.lib.opensongimport import OpenSongImport
+from openlp.core.lib.db import Manager
+from openlp.plugins.songs.lib.db import init_schema
+from openlp.plugins.songs.songsplugin import SongsPlugin
+import sys
+
+def test():
+ manager = Manager(u'songs', init_schema)
+ o = OpenSongImport(manager)
+ o.do_import(u'test.opensong', commit=False)
+ o.finish()
+ o.song.print_song()
+ assert o.song.copyright == u'2010 Martin Thompson'
+ assert o.song.authors == [u'Martià Thómpson']
+ assert o.song.title == u'Martins Test'
+ assert o.song.alternate_title == u''
+ assert o.song.song_number == u'1'
+ assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song.verses
+ assert [u'C1', u'Chorus 1'] in o.song.verses
+ assert [u'C2', u'Chorus 2'] in o.song.verses
+ assert not [u'C3', u'Chorus 3'] in o.song.verses
+ assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song.verses
+ assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song.verses
+ assert o.song.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
+ assert o.song.ccli_number == u'Blah'
+ assert o.song.theme_name == u'TestTheme, TestAltTheme'
+ o.do_import(u'test.opensong.zip', commit=False)
+ o.finish()
+ o.song.print_song()
+ assert o.song.copyright == u'2010 Martin Thompson'
+ assert o.song.authors == [u'Martià Thómpson']
+ assert o.song.title == u'Martins Test'
+ assert o.song.alternate_title == u''
+ assert o.song.song_number == u'1'
+ assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song.verses
+ assert [u'C1', u'Chorus 1'] in o.song.verses
+ assert [u'C2', u'Chorus 2'] in o.song.verses
+ assert not [u'C3', u'Chorus 3'] in o.song.verses
+ assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song.verses
+ assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song.verses
+ assert o.song.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
+
+ o = OpenSongImport(manager)
+ o.do_import(u'test2.opensong', commit=False)
+ # o.finish()
+ o.song.print_song()
+ assert o.song.copyright == u'2010 Martin Thompson'
+ assert o.song.authors == [u'Martin Thompson']
+ assert o.song.title == u'Martins 2nd Test'
+ assert o.song.alternate_title == u''
+ assert o.song.song_number == u'2'
+ print o.song.verses
+ assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song.verses
+ assert [u'C1', u'Chorus 1'] in o.song.verses
+ assert [u'C2', u'Chorus 2'] in o.song.verses
+ assert not [u'C3', u'Chorus 3'] in o.song.verses
+ assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song.verses
+ assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song.verses
+ print o.song.verse_order_list
+ assert o.song.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
+
+ print "Tests passed"
+ pass
+
+if __name__ == "__main__":
+ test()
=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py 2010-07-12 21:11:00 +0000
+++ openlp/plugins/songs/songsplugin.py 2010-07-14 20:55:54 +0000
@@ -39,6 +39,8 @@
except ImportError:
OOo_available = False
+from openlp.plugins.songs.lib import OpenSongImport
+
log = logging.getLogger(__name__)
class SongsPlugin(Plugin):
@@ -137,6 +139,25 @@
QtCore.SIGNAL(u'triggered()'), self.onImportSofItemClick)
QtCore.QObject.connect(self.ImportOooItem,
QtCore.SIGNAL(u'triggered()'), self.onImportOooItemClick)
+ # OpenSong import menu item - will be removed and the
+ # functionality will be contained within the import wizard
+ self.ImportOpenSongItem = QtGui.QAction(import_menu)
+ self.ImportOpenSongItem.setObjectName(u'ImportOpenSongItem')
+ self.ImportOpenSongItem.setText(
+ translate('SongsPlugin',
+ 'OpenSong (temp menu item)'))
+ self.ImportOpenSongItem.setToolTip(
+ translate('SongsPlugin',
+ 'Import songs from OpenSong files' +
+ '(either raw text or ZIPfiles)'))
+ self.ImportOpenSongItem.setStatusTip(
+ translate('SongsPlugin',
+ 'Import songs from OpenSong files' +
+ '(either raw text or ZIPfiles)'))
+ import_menu.addAction(self.ImportOpenSongItem)
+ QtCore.QObject.connect(self.ImportOpenSongItem,
+ QtCore.SIGNAL(u'triggered()'), self.onImportOpenSongItemClick)
+
def addExportMenuItem(self, export_menu):
"""
@@ -177,6 +198,26 @@
QtGui.QMessageBox.Ok)
Receiver.send_message(u'songs_load_list')
+ def onImportOpenSongItemClick(self):
+ filenames = QtGui.QFileDialog.getOpenFileNames(
+ None, translate('SongsPlugin',
+ 'Open OpenSong file'),
+ u'', u'All files (*.*)')
+ try:
+ for filename in filenames:
+ importer = OpenSongImport(self.manager)
+ importer.do_import(unicode(filename))
+ except:
+ log.exception('Could not import OpenSong file')
+ QtGui.QMessageBox.critical(None,
+ translate('SongsPlugin',
+ 'Import Error'),
+ translate('SongsPlugin',
+ 'Error importing OpenSong file'),
+ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
+ QtGui.QMessageBox.Ok)
+ Receiver.send_message(u'songs_load_list')
+
def onImportOooItemClick(self):
filenames = QtGui.QFileDialog.getOpenFileNames(
None, translate('SongsPlugin',
Follow ups