openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #02372
[Merge] lp:~mjthompson/openlp/opensong_import into lp:openlp
Martin Thompson has proposed merging lp:~mjthompson/openlp/opensong_import into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
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.
Temporary GUI option for import created, as with SOF import.
Still todo
- make it work on files with non-ASCII chars in.
- check the content of database post import (I've done a little bit, but it could do with more eyes at some point)
--
https://code.launchpad.net/~mjthompson/openlp/opensong_import/+merge/29420
Your team OpenLP Core is requested to review the proposed merge of lp:~mjthompson/openlp/opensong_import into 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-07 20:28:40 +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-07 20:28:40 +0000
@@ -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)
=== 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-07 20:28:40 +0000
@@ -0,0 +1,231 @@
+# -*- 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=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
+ if l[0] == 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:
+ versenum = u''
+ 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 = {}
+ 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 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-07 20:28:40 +0000
@@ -51,8 +51,8 @@
self.alternate_title = u''
self.copyright = u''
self.comment = u''
- self.theme_name = u''
- self.ccli_number = u''
+ self.theme = u''
+ self.song_cclino = u''
self.authors = []
self.topics = []
self.song_book_name = u''
@@ -163,6 +163,12 @@
"""
self.song_number = song_number
+ def set_ccli_number(self, ccli_number):
+ """
+ Set the ccli number
+ """
+ self.ccli_number = ccli_number
+
def set_song_book(self, song_book, publisher):
"""
Set the song book name and publisher
@@ -297,8 +303,8 @@
song.verse_order = u' '.join(self.verse_order_list)
song.copyright = self.copyright
song.comment = self.comment
- song.theme_name = self.theme_name
- song.ccli_number = self.ccli_number
+ song.theme = self.theme
+ song.song_cclino = self.song_cclino
for authortext in self.authors:
author = self.manager.get_object_filtered(Author,
Author.display_name == authortext)
@@ -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
@@ -353,7 +358,7 @@
print u'TOPIC: ' + topictext
if self.comment:
print u'COMMENT: ' + self.comment
- if self.theme_name:
- print u'THEME: ' + self.theme_name
- if self.ccli_number:
- print u'CCLI: ' + self.ccli_number
+ if self.theme:
+ print u'THEME: ' + self.theme
+ if self.song_cclino:
+ print u'CCLI: ' + self.song_cclino
=== 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-07 20:28:40 +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
@@ -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
=== 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-07 20:28:40 +0000
@@ -0,0 +1,51 @@
+<?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-07 20:28:40 +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-07 20:28:40 +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-07 20:28:40 +0000
@@ -0,0 +1,55 @@
+from openlp.plugins.songs.lib.opensongimport import OpenSongImport
+from openlp.plugins.songs.lib.manager import SongManager
+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=SongManager()
+ 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-07 20:28:40 +0000
@@ -0,0 +1,89 @@
+# -*- 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.plugins.songs.lib.manager import SongManager
+import sys
+
+def test():
+ manager = SongManager()
+ 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'C', 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'C', u'V2', u'C2', u'V3', u'B1', u'V1']
+ assert o.song.ccli_number == u'Blah'
+ print u':%s:'%o.song.theme
+ assert o.song.theme == 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'C', 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'C', 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-05 16:00:48 +0000
+++ openlp/plugins/songs/songsplugin.py 2010-07-07 20:28:40 +0000
@@ -39,6 +39,8 @@
except ImportError:
OOo_available = False
+from openlp.plugins.songs.lib import OpenSongImport
+
log = logging.getLogger(__name__)
class SongsPlugin(Plugin):
@@ -136,6 +138,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):
"""
@@ -176,6 +197,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'OpenSong file (*. *.zip *.ZIP)')
+ 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