Split song and sof specifics

This commit is contained in:
Jonathan Corwin 2010-04-01 22:36:03 +01:00
parent 949dfd927d
commit 1f41039e07
2 changed files with 597 additions and 266 deletions

View File

@ -31,8 +31,9 @@
import re
import os
import time
import time
from PyQt4 import QtCore
from songimport import SongImport
if os.name == u'nt':
from win32com.client import Dispatch
@ -48,19 +49,44 @@ else:
from com.sun.star.awt.FontSlant import ITALIC
from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH
class sofimport:
def __init__(self):
class SofImport(object):
"""
Import songs provided on disks with the Songs of Fellowship music books
VOLS1_2.RTF, sof3words.rtf and sof4words.rtf
Use OpenOffice.org Writer for processing the rtf file
The three books are not only inconsistant with each other, they are
inconsistant in themselves too with their formatting. Not only this, but
the 1+2 book does not space out verses correctly. This script attempts
to sort it out, but doesn't get it 100% right. But better than having to
type them all out!
It attempts to detect italiced verses, and treats these as choruses in
the verse ordering. Again not perfect, but a start.
"""
def __init__(self, songmanager):
"""
Initialise the class. Requires a songmanager class which is passed
to SongImport for writing song to disk
"""
self.song = None
self.new_song()
self.manager = songmanager
def start_ooo(self):
"""
Start OpenOffice.org process
TODO: The presentation/Impress plugin may already have it running
"""
if os.name == u'nt':
manager = Dispatch(u'com.sun.star.ServiceManager')
manager._FlagAsMethod(u'Bridge_GetStruct')
manager._FlagAsMethod(u'Bridge_GetValueObject')
self.desktop = manager.createInstance(u'com.sun.star.frame.Desktop')
else:
cmd = u'openoffice.org -nologo -norestore -minimized -invisible -nofirststartwizard -accept="socket,host=localhost,port=2002;urp;"'
cmd = u'openoffice.org -nologo -norestore -minimized -invisible ' \
+ u'-nofirststartwizard ' \
+ '-accept="socket,host=localhost,port=2002;urp;"'
process = QtCore.QProcess()
process.startDetached(cmd)
process.waitForStarted()
@ -69,17 +95,22 @@ class sofimport:
u'com.sun.star.bridge.UnoUrlResolver', context)
ctx = None
loop = 0
while ctx is None and loop < 3:
while ctx is None and loop < 5:
try:
ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
except:
time.sleep(1)
loop += 1
ctx = resolver.resolve(u'uno:socket,host=localhost,' \
+ 'port=2002;urp;StarOffice.ComponentContext')
except:
pass
time.sleep(1)
loop += 1
manager = ctx.ServiceManager
self.desktop = manager.createInstanceWithContext(
"com.sun.star.frame.Desktop", ctx )
def open_sof_file(self, filepath):
def open_ooo_file(self, filepath):
"""
Open the passed file in OpenOffice.org Writer
"""
if os.name == u'nt':
url = u'file:///' + filepath.replace(u'\\', u'/')
url = url.replace(u':', u'|').replace(u' ', u'%20')
@ -91,10 +122,18 @@ class sofimport:
0, properties)
def close_ooo(self):
"""
Close down OpenOffice.org.
TODO: Further checks that it have other docs open, e.g. Impress!
"""
self.desktop.terminate()
def process_doc(self):
def process_doc(self):
"""
Process the RTF file, a paragraph at a time
"""
self.blanklines = 0
self.new_song()
paragraphs = self.document.getText().createEnumeration()
while paragraphs.hasMoreElements():
paragraph = paragraphs.nextElement()
@ -105,6 +144,16 @@ class sofimport:
self.song = None
def process_paragraph(self, paragraph):
"""
Process a paragraph.
In the first book, a paragraph is a single line. In the latter ones
they may contain multiple lines.
Each paragraph contains textportions. Each textportion has it's own
styling, e.g. italics, bold etc.
Also check for page breaks, which indicates a new song in books 1+2.
In later books, there may not be line breaks, so check for 3 or more
newlines
"""
text = u''
textportions = paragraph.createEnumeration()
while textportions.hasMoreElements():
@ -120,29 +169,36 @@ class sofimport:
text = u''
self.process_paragraph_text(text)
def process_paragraph_text(self, text):
def process_paragraph_text(self, text):
"""
Split the paragraph text into multiple lines and process
"""
for line in text.split(u'\n'):
self.process_paragraph_line(line)
if self.blanklines > 2:
self.new_song()
def process_paragraph_line(self, text):
def process_paragraph_line(self, text):
"""
Process a single line. Throw away that text which isn't relevant, i.e.
stuff that appears at the end of the song.
Anything that is OK, append to the current verse
"""
text = text.strip()
if text == u'':
self.blanklines += 1
if self.blanklines > 1:
return
if self.song.title != u'':
self.song.finish_verse()
if self.song.get_title() != u'':
self.finish_verse()
return
#print ">" + text + "<"
self.blanklines = 0
if self.skip_to_close_bracket:
if text.endswith(u')'):
self.skip_to_close_bracket = False
return
if text.startswith(u'CCL Licence'):
self.in_chorus = False
self.italics = False
return
if text == u'A Songs of Fellowship Worship Resource':
return
@ -151,299 +207,315 @@ class sofimport:
self.skip_to_close_bracket = True
return
if text.startswith(u'Copyright'):
self.song.copyright = text
self.song.add_copyright(text)
return
if text == u'(Repeat)':
self.finish_verse()
self.song.repeat_verse()
return
if self.song.title == u'':
if self.song.copyright == u'':
self.song.add_author(text)
if self.song.get_title() == u'':
if self.song.get_copyright() == u'':
self.add_author(text)
else:
self.song.copyright += u' ' + text
self.song.add_copyright(text)
return
self.song.add_verse_line(text, self.in_chorus)
self.add_verse_line(text)
def process_textportion(self, textportion):
def process_textportion(self, textportion):
"""
Process a text portion. Here we just get the text and detect if
it's bold or italics. If it's bold then its a song number or song title.
Song titles are in all capitals, so we must bring the capitalization
into line
"""
text = textportion.getString()
text = self.tidy_text(text)
if text.strip() == u'':
return text
if textportion.CharWeight == BOLD:
boldtext = text.strip()
if boldtext.isdigit() and self.song.songnumber == 0:
self.song.songnumber = int(boldtext)
if boldtext.isdigit() and self.song.get_song_number() == '':
self.add_songnumber(boldtext)
return u''
if self.song.title == u'':
text = self.uncap_text(text)
title = text.strip()
if title.startswith(u'\''):
title = title[1:]
if title.endswith(u','):
title = title[:-1]
self.song.title = title
if self.song.get_title() == u'':
text = self.uncap_text(text)
self.add_title(text)
return text
if text.strip().startswith(u'('):
return text
self.in_chorus = (textportion.CharPosture == ITALIC)
self.italics = (textportion.CharPosture == ITALIC)
return text
def new_song(self):
def new_song(self):
"""
A change of song. Store the old, create a new
... but only if the last song was complete. If not, stick with it
"""
if self.song:
if not self.song.finish():
self.finish_verse()
if not self.song.check_complete():
return
self.song = sofsong()
self.song.finish()
self.song = SongImport(self.manager)
self.skip_to_close_bracket = False
self.in_chorus = False
def tidy_text(self, text):
text = text.replace(u'\t', u' ')
text = text.replace(u'\r', u'\n')
text = text.replace(u'\u2018', u'\'')
text = text.replace(u'\u2019', u'\'')
text = text.replace(u'\u201c', u'"')
text = text.replace(u'\u201d', u'"')
text = text.replace(u'\u2026', u'...')
text = text.replace(u'\u2013', u'-')
text = text.replace(u'\u2014', u'-')
return text
def uncap_text(self, text):
textarr = re.split(u'(\W+)', text)
textarr[0] = textarr[0].capitalize()
for i in range(1, len(textarr)):
# Do not translate these. Fixed strings in SOF song file
if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY',
u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER',
u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE',
u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS',
u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH',
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
u'FATHER\'S', u'ELIJAH'):
textarr[i] = textarr[i].capitalize()
else:
textarr[i] = textarr[i].lower()
text = u''.join(textarr)
return text
class sofsong:
def __init__(self):
self.songnumber = 0
self.title = u''
self.ischorus = False
self.versecount = 0
self.choruscount = 0
self.verses = []
self.order = []
self.authors = []
self.copyright = u''
self.book = u''
self.currentverse = u''
self.is_chorus = False
self.italics = False
self.currentverse = u''
def finish_verse(self):
def add_songnumber(self, song_no):
"""
Add a song number, store as alternate title. Also use the song
number to work out which songbook we're in
"""
self.song.set_song_number(song_no)
if int(song_no) <= 640:
self.song.set_song_book(u'Songs of Fellowship 1',
'Kingsway\'s Thankyou Music')
elif int(song_no) <= 1150:
self.song.set_song_book(u'Songs of Fellowship 2',
'Kingsway\'s Thankyou Music')
elif int(song_no) <= 1690:
self.song.set_song_book(u'Songs of Fellowship 3',
'Kingsway\'s Thankyou Music')
else:
self.song.set_song_book(u'Songs of Fellowship 4',
'Kingsway\'s Thankyou Music')
def add_title(self, text):
"""
Add the title to the song. Strip some leading/trailing punctuation that
we don't want in a title
"""
title = text.strip()
if title.startswith(u'\''):
title = title[1:]
if title.endswith(u','):
title = title[:-1]
self.song.set_title(title)
def add_author(self, text):
"""
Add the author. OpenLP stores them individually so split by 'and', '&'
and comma.
However need to check for "Mr and Mrs Smith" and turn it to
"Mr Smith" and "Mrs Smith".
"""
text = text.replace(u' and ', u' & ')
for author in text.split(u','):
authors = author.split(u'&')
for i in range(len(authors)):
author2 = authors[i].strip()
if author2.find(u' ') == -1 and i < len(authors) - 1:
author2 = author2 + u' ' \
+ authors[i + 1].strip().split(u' ')[-1]
self.song.add_author(author2)
def add_verse_line(self, text):
"""
Add a line to the current verse. If the formatting has changed and
we're beyond the second line of first verse, then this indicates
a change of verse. Italics are a chorus
"""
if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or
(self.currentverse.count(u'\n') > 1)):
self.finish_verse()
if self.italics:
self.is_chorus = True
self.currentverse += text + u'\n'
def finish_verse(self):
"""
Verse is finished, store it. Note in book 1+2, some songs are formatted
incorrectly. Here we try and split songs with missing line breaks into
the correct number of verses.
"""
if self.currentverse.strip() == u'':
return
if self.ischorus:
splitat = None
else:
splitat = self.verse_splits()
return
if self.is_chorus:
versetag = 'C'
splitat = None
else:
versetag = 'V'
splitat = self.verse_splits(self.song.get_song_number())
if splitat:
ln = 0
verse = u''
for line in self.currentverse.split(u'\n'):
ln += 1
if line == u'' or ln > splitat:
self.append_verse(verse)
ln = 0
if line == u'' or ln > splitat:
self.song.add_verse(verse, versetag)
ln = 0
if line:
verse = line + u'\n'
else:
verse = line + u'\n'
else:
verse = u''
else:
verse += line + u'\n'
if verse:
self.append_verse(verse)
self.song.add_verse(verse, versetag)
else:
self.append_verse(self.currentverse)
self.song.add_verse(self.currentverse, versetag)
self.currentverse = u''
self.ischorus = False
self.is_chorus = False
def append_verse(self, verse):
if self.ischorus:
self.choruscount += 1
versetag = u'C' + unicode(self.choruscount)
else:
self.versecount += 1
versetag = u'V' + unicode(self.versecount)
self.verses.append([versetag, verse])
self.order.append(versetag)
if self.choruscount > 0 and not self.ischorus:
self.order.append(u'C' + unicode(self.choruscount))
def tidy_text(self, text):
"""
Get rid of some dodgy unicode and formatting characters we're not
interested in. Some can be converted to ascii.
"""
text = text.replace(u'\t', u' ')
text = text.replace(u'\r', u'\n')
text = text.replace(u'\u2018', u'\'')
text = text.replace(u'\u2019', u'\'')
text = text.replace(u'\u201c', u'"')
text = text.replace(u'\u201d', u'"')
text = text.replace(u'\u2026', u'...')
text = text.replace(u'\u2013', u'-')
text = text.replace(u'\u2014', u'-')
return text
def repeat_verse(self):
self.finish_verse()
self.order.append(self.order[-1])
def add_verse_line(self, text, inchorus):
if inchorus != self.ischorus and ((len(self.verses) > 0) or
(self.currentverse.count(u'\n') > 1)):
self.finish_verse()
if inchorus:
self.ischorus = True
self.currentverse += text + u'\n'
def add_author(self, text):
text = text.replace(u' and ', u' & ')
for author in text.split(u','):
authors = author.split(u'&')
for i in range(len(authors)):
author2 = authors[i].strip()
if author2.find(u' ') == -1 and i < len(authors) - 1:
author2 = author2 + u' ' + authors[i + 1].split(u' ')[-1]
self.authors.append(author2)
def uncap_text(self, text):
"""
Words in the title are in all capitals, so we lowercase them.
However some of these words, e.g. referring to God need a leading
capital letter.
There is a complicated word "One", which is sometimes lower and
sometimes upper depending on context. Never mind, keep it lower.
"""
textarr = re.split(u'(\W+)', text)
textarr[0] = textarr[0].capitalize()
for i in range(1, len(textarr)):
# Do not translate these. Fixed strings in SOF song file
if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY',
u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER',
u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE',
u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS',
u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH',
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
u'FATHER\'S', u'ELIJAH'):
textarr[i] = textarr[i].capitalize()
else:
textarr[i] = textarr[i].lower()
text = u''.join(textarr)
return text
def finish(self):
self.finish_verse()
if self.songnumber == 0 \
or self.title == u'' \
or len(self.verses) == 0:
return False
if len(self.authors) == 0:
self.authors.append(u'Author Unknown')
if self.songnumber <= 640:
self.book = u'Songs of Fellowship 1'
elif self.songnumber <= 1150:
self.book = u'Songs of Fellowship 2'
elif self.songnumber <= 1690:
self.book = u'Songs of Fellowship 3'
else:
self.book = u'Songs of Fellowship 4'
self.print_song()
return True
def print_song(self):
print u'===== TITLE: ' + self.title + u' ====='
print u'ALTTITLE: ' + unicode(self.songnumber)
for (verselabel, verse) in self.verses:
print u'VERSE ' + verselabel + u': ' + verse
print u'ORDER: ' + unicode(self.order)
for author in self.authors:
print u'AUTHORS: ' + author
print u'COPYRIGHT: ' + self.copyright
print u'BOOK: ' + self.book
def verse_splits(self):
def verse_splits(self, song_number):
"""
Because someone at Kingsway forgot to check the 1+2 RTF file,
some verses were not formatted correctly.
"""
if self.songnumber == 11: return 8
if self.songnumber == 18: return 5
if self.songnumber == 21: return 6
if self.songnumber == 23: return 4
if self.songnumber == 24: return 7
if self.songnumber == 27: return 4
if self.songnumber == 31: return 6
if self.songnumber == 49: return 4
if self.songnumber == 50: return 8
if self.songnumber == 70: return 4
if self.songnumber == 75: return 8
if self.songnumber == 79: return 6
if self.songnumber == 97: return 7
if self.songnumber == 107: return 4
if self.songnumber == 109: return 4
if self.songnumber == 133: return 4
if self.songnumber == 155: return 10
if self.songnumber == 156: return 8
if self.songnumber == 171: return 4
if self.songnumber == 188: return 7
if self.songnumber == 192: return 4
if self.songnumber == 208: return 8
if self.songnumber == 215: return 8
if self.songnumber == 220: return 4
if self.songnumber == 247: return 6
if self.songnumber == 248: return 6
if self.songnumber == 251: return 8
if self.songnumber == 295: return 8
if self.songnumber == 307: return 5
if self.songnumber == 314: return 6
if self.songnumber == 325: return 8
if self.songnumber == 386: return 6
if self.songnumber == 415: return 4
if self.songnumber == 426: return 4
if self.songnumber == 434: return 5
if self.songnumber == 437: return 4
if self.songnumber == 438: return 6
if self.songnumber == 456: return 8
if self.songnumber == 461: return 4
if self.songnumber == 469: return 4
if self.songnumber == 470: return 5
if self.songnumber == 476: return 6
if self.songnumber == 477: return 7
if self.songnumber == 480: return 8
if self.songnumber == 482: return 4
if self.songnumber == 512: return 4
if self.songnumber == 513: return 8
if self.songnumber == 518: return 5
if self.songnumber == 520: return 4
if self.songnumber == 523: return 6
if self.songnumber == 526: return 8
if self.songnumber == 527: return 4
if self.songnumber == 529: return 4
if self.songnumber == 537: return 4
if self.songnumber == 555: return 6
if self.songnumber == 581: return 4
if self.songnumber == 589: return 6
if self.songnumber == 590: return 4
if self.songnumber == 593: return 8
if self.songnumber == 596: return 4
if self.songnumber == 610: return 6
if self.songnumber == 611: return 6
if self.songnumber == 619: return 8
if self.songnumber == 645: return 5
if self.songnumber == 653: return 6
if self.songnumber == 683: return 7
if self.songnumber == 686: return 4
if self.songnumber == 697: return 8
if self.songnumber == 698: return 4
if self.songnumber == 704: return 6
if self.songnumber == 716: return 4
if self.songnumber == 717: return 6
if self.songnumber == 730: return 4
if self.songnumber == 731: return 8
if self.songnumber == 732: return 8
if self.songnumber == 738: return 4
if self.songnumber == 756: return 9
if self.songnumber == 815: return 6
if self.songnumber == 830: return 8
if self.songnumber == 831: return 4
if self.songnumber == 876: return 6
if self.songnumber == 877: return 6
if self.songnumber == 892: return 4
if self.songnumber == 894: return 6
if self.songnumber == 902: return 8
if self.songnumber == 905: return 8
if self.songnumber == 921: return 6
if self.songnumber == 940: return 7
if self.songnumber == 955: return 9
if self.songnumber == 968: return 8
if self.songnumber == 972: return 7
if self.songnumber == 974: return 4
if self.songnumber == 988: return 6
if self.songnumber == 991: return 5
if self.songnumber == 1002: return 8
if self.songnumber == 1024: return 8
if self.songnumber == 1044: return 9
if self.songnumber == 1088: return 6
if self.songnumber == 1117: return 6
if self.songnumber == 1119: return 7
if song_number == 11: return 8
if song_number == 18: return 5
if song_number == 21: return 6
if song_number == 23: return 4
if song_number == 24: return 7
if song_number == 27: return 4
if song_number == 31: return 6
if song_number == 49: return 4
if song_number == 50: return 8
if song_number == 70: return 4
if song_number == 75: return 8
if song_number == 79: return 6
if song_number == 97: return 7
if song_number == 107: return 4
if song_number == 109: return 4
if song_number == 133: return 4
if song_number == 155: return 10
if song_number == 156: return 8
if song_number == 171: return 4
if song_number == 188: return 7
if song_number == 192: return 4
if song_number == 208: return 8
if song_number == 215: return 8
if song_number == 220: return 4
if song_number == 247: return 6
if song_number == 248: return 6
if song_number == 251: return 8
if song_number == 295: return 8
if song_number == 307: return 5
if song_number == 314: return 6
if song_number == 325: return 8
if song_number == 386: return 6
if song_number == 415: return 4
if song_number == 426: return 4
if song_number == 434: return 5
if song_number == 437: return 4
if song_number == 438: return 6
if song_number == 456: return 8
if song_number == 461: return 4
if song_number == 469: return 4
if song_number == 470: return 5
if song_number == 476: return 6
if song_number == 477: return 7
if song_number == 480: return 8
if song_number == 482: return 4
if song_number == 512: return 4
if song_number == 513: return 8
if song_number == 518: return 5
if song_number == 520: return 4
if song_number == 523: return 6
if song_number == 526: return 8
if song_number == 527: return 4
if song_number == 529: return 4
if song_number == 537: return 4
if song_number == 555: return 6
if song_number == 581: return 4
if song_number == 589: return 6
if song_number == 590: return 4
if song_number == 593: return 8
if song_number == 596: return 4
if song_number == 610: return 6
if song_number == 611: return 6
if song_number == 619: return 8
if song_number == 645: return 5
if song_number == 653: return 6
if song_number == 683: return 7
if song_number == 686: return 4
if song_number == 697: return 8
if song_number == 698: return 4
if song_number == 704: return 6
if song_number == 716: return 4
if song_number == 717: return 6
if song_number == 730: return 4
if song_number == 731: return 8
if song_number == 732: return 8
if song_number == 738: return 4
if song_number == 756: return 9
if song_number == 815: return 6
if song_number == 830: return 8
if song_number == 831: return 4
if song_number == 876: return 6
if song_number == 877: return 6
if song_number == 892: return 4
if song_number == 894: return 6
if song_number == 902: return 8
if song_number == 905: return 8
if song_number == 921: return 6
if song_number == 940: return 7
if song_number == 955: return 9
if song_number == 968: return 8
if song_number == 972: return 7
if song_number == 974: return 4
if song_number == 988: return 6
if song_number == 991: return 5
if song_number == 1002: return 8
if song_number == 1024: return 8
if song_number == 1044: return 9
if song_number == 1088: return 6
if song_number == 1117: return 6
if song_number == 1119: return 7
return None
sof = sofimport()
#config = None
man = None
#man = SongManager(config)
sof = SofImport(man)
sof.start_ooo()
sof.open_sof_file(u'/home/jonathan/sof.rtf')
#sof.open_sof_file(u'c:\users\jonathan\Desktop\sof3words.rtf')
#sof.open_sof_file(u'c:\users\jonathan\Desktop\sof4words.rtf')
#sof.open_ooo_file(u'/home/jonathan/sof.rtf')
sof.open_ooo_file(u'/home/jonathan/Documents/VOLS1_2.RTF')
#sof.open_ooo_file(u'c:\users\jonathan\Desktop\sof3words.rtf')
#sof.open_ooo_file(u'c:\users\jonathan\Desktop\sof4words.rtf')
sof.process_doc()
sof.close_ooo()

View File

@ -0,0 +1,259 @@
# -*- 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 string
from openlp.core.lib import SongXMLBuilder
from openlp.plugins.songs.lib.models import Song
class SongImport(object):
"""
Helper class for import a song from a third party source into OpenLP
This class just takes the raw strings, and will work out for itself
whether the authors etc already exist and add them or refer to them
as necessary
"""
def __init__(self, song_manager):
"""
Initialise and create defaults for properties
song_manager is an instance of a SongManager, through which all
database access is performed
"""
self.song_manager = song_manager
self.title = u''
self.song_number = u''
self.copyright = u''
self.comment = u''
self.theme_name = u''
self.ccli_number = u''
self.authors = []
self.topics = []
self.song_book_name = u''
self.song_book_pub = u''
self.verse_order_list = []
self.verses = []
self.versecount = 0
self.choruscount = 0
def get_title(self):
"""
Return the title
"""
return self.title
def get_copyright(self):
"""
Return the copyright
"""
return self.copyright
def get_song_number(self):
"""
Return the song number (also known as alternate title)
"""
return self.song_number
def set_title(self, title):
"""
Set the title
"""
self.title = title
def set_song_number(self, song_number):
"""
Set the song number/alternate title
"""
self.song_number = song_number
def set_song_book(self, song_book, publisher):
"""
Set the song book name and publisher
"""
self.song_book_name = song_book
self.song_book_pub = publisher
def add_copyright(self, copyright):
"""
Build the copyright field
"""
if self.copyright != u'':
self.copyright += ' '
self.copyright += copyright
def add_author(self, text):
"""
Add an author to the list
"""
self.authors.append(text)
def add_verse(self, verse, versetag):
"""
Add a verse. This is the whole verse, lines split by \n
Verse tag can be V1/C1/B1 etc, or 'V' and 'C' (will count the verses/
choruses itself) or None, where it will assume verse
It will also attempt to detect duplicates. In this case it will just
add to the verse order
"""
for (oldversetag, oldverse) in self.verses:
if oldverse.strip() == verse.strip():
self.verse_order_list.append(oldversetag)
return
if versetag == u'C':
self.choruscount += 1
versetag += unicode(self.choruscount)
if versetag == u'V' or not versetag:
self.versecount += 1
versetag = u'V' + unicode(self.versecount)
self.verses.append([versetag, verse])
self.verse_order_list.append(versetag)
if self.choruscount > 0 and not versetag.startswith(u'C'):
self.verse_order_list.append(u'C1')
def repeat_verse(self):
"""
Repeat the previous verse in the verse order
"""
self.verse_order_list.append(self.verse_order_list[-1])
def check_complete(self):
"""
Check the mandatory fields are entered (i.e. title and a verse)
Author not checked here, if no author then "Author unknown" is
automatically added
"""
if self.title == u'' or len(self.verses) == 0:
return False
else:
return True
def remove_punctuation(self, text):
"""
Remove punctuation from the string for searchable fields
"""
return text.translate(string.maketrans(u'',u''), string.punctuation)
def finish(self):
"""
All fields have been set to this song. Write it away
"""
if len(self.authors) == 0:
self.authors.append(u'Author unknown')
#self.commit_song()
self.print_song()
def commit_song():
"""
Write the song and it's fields to disk
"""
song = Song()
song.title = self.title
song.search_title = self.remove_punctuation(self.title)
song.song_number = self.song_number
song.search_lyrics = u''
sxml = SongXMLBuilder()
sxml.new_document()
sxml.add_lyrics_to_song()
for (versetag, versetext) in self.verses:
if versetag[0] == u'C':
versetype = u'Chorus'
elif versetag[0] == u'V':
versetype = u'Verse'
elif versetag[0] == u'B':
versetype = u'Bridge'
elif versetag[0] == u'I':
versetype = u'Intro'
elif versetag[0] == u'P':
versetype = u'Prechorus'
elif versetag[0] == u'E':
versetype = u'Ending'
else:
versetype = u'Other'
sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext)
song.search_lyrics += u' ' + self.remove_punctuation(versetext)
song.lyrics = unicode(sxml.extract_xml(), u'utf-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
for authortext in self.authors:
author = None
# read the author here
if author is None:
author = Author()
author.display_name = authortext
author.last_name = authortext.split(u' ')[-1]
author.first_name = u' '.join(authortext.split(u' ')[:-1])
# write the author here
song.authors.append(author)
if self.song_book_name:
song_book = None
# read the book here
if song_book is None:
song_book = Book()
song_book.name = self.song_book_name
song_book.publisher = self.song_book_pub
# write the song book here
song.song_book_id = song_book.id
for topictext in self.topics:
topic = None
# read the topic here
if topic is None:
topic = Topic()
topic.name = topictext
# write the topic here
song.topics.append(topictext)
# write the song here
def print_song(self):
"""
For debugging
"""
print u'========================================' \
+ u'========================================'
print u'TITLE: ' + self.title
for (versetag, versetext) in self.verses:
print u'VERSE ' + versetag + u': ' + versetext
print u'ORDER: ' + u' '.join(self.verse_order_list)
for author in self.authors:
print u'AUTHOR: ' + author
if self.copyright:
print u'COPYRIGHT: ' + self.copyright
if self.song_book_name:
print u'BOOK: ' + self.song_book_name
if self.song_number:
print u'NUMBER: ' + self.song_number
for topictext in self.topics:
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