openlp/openlp/plugins/songs/lib/songimport.py

373 lines
14 KiB
Python
Raw Normal View History

2010-04-01 21:36:03 +00:00
# -*- 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
2010-04-19 18:43:20 +00:00
from PyQt4 import QtGui
2010-04-12 07:22:56 +00:00
from openlp.core.lib import SongXMLBuilder
2010-04-02 14:10:10 +00:00
from openlp.plugins.songs.lib.models import Song, Author, Topic, Book
2010-04-12 07:22:56 +00:00
2010-04-01 21:36:03 +00:00
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
2010-04-12 07:22:56 +00:00
"""
2010-04-02 14:10:10 +00:00
self.manager = song_manager
2010-04-12 07:22:56 +00:00
self.title = u''
2010-04-01 21:36:03 +00:00
self.song_number = u''
2010-04-02 23:24:51 +00:00
self.alternate_title = u''
2010-04-12 07:22:56 +00:00
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
self.copyright_string = unicode(QtGui.QApplication.translate( \
u'SongImport', u'copyright'))
self.copyright_symbol = unicode(QtGui.QApplication.translate( \
u'SongImport', u'©'))
@staticmethod
def process_songs_text(manager, text):
songs = []
2010-04-12 21:49:56 +00:00
songtexts = SongImport.tidy_text(text).split(u'\f')
song = SongImport(manager)
2010-04-12 07:22:56 +00:00
for songtext in songtexts:
2010-04-12 21:49:56 +00:00
if songtext.strip():
2010-04-12 07:22:56 +00:00
song.process_song_text(songtext.strip())
2010-04-12 21:49:56 +00:00
if song.check_complete():
songs.append(song)
song = SongImport(manager)
if song.check_complete():
songs.append(song)
2010-04-12 07:22:56 +00:00
return songs
@staticmethod
def tidy_text(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\n', u'\n')
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'-')
# Remove surplus blank lines, spaces, trailing/leading spaces
while text.find(u' ') >= 0:
text = text.replace(u' ', u' ')
2010-04-12 21:49:56 +00:00
text = text.replace(u'\n ', u'\n')
text = text.replace(u' \n', u'\n')
text = text.replace(u'\n\n\n\n\n', u'\f')
text = text.replace(u'\f ', u'\f')
text = text.replace(u' \f', u'\f')
while text.find(u'\f\f') >= 0:
text = text.replace(u'\f\f', u'\f')
2010-04-12 07:22:56 +00:00
return text
def process_song_text(self, text):
versetexts = text.split(u'\n\n')
for versetext in versetexts:
if versetext.strip() != u'':
self.process_verse_text(versetext.strip())
def process_verse_text(self, text):
lines = text.split(u'\n')
if text.lower().find(self.copyright_string) >= 0 \
or text.lower().find(self.copyright_symbol) >= 0:
copyright_found = False
for line in lines:
if copyright_found or line.lower().find(self.copyright_string) >= 0\
or line.lower().find(self.copyright_symbol) >= 0:
copyright_found = True
self.add_copyright(line)
else:
self.parse_author(line)
return
if len(lines) == 1:
self.parse_author(lines[0])
return
if not self.get_title():
self.set_title(lines[0])
self.add_verse(text)
2010-04-01 21:36:03 +00:00
def get_title(self):
"""
Return the title
2010-04-12 07:22:56 +00:00
"""
return self.title
2010-04-01 21:36:03 +00:00
def get_copyright(self):
"""
Return the copyright
2010-04-12 07:22:56 +00:00
"""
return self.copyright
2010-04-01 21:36:03 +00:00
def get_song_number(self):
"""
2010-04-02 23:24:51 +00:00
Return the song number
2010-04-12 07:22:56 +00:00
"""
return self.song_number
2010-04-01 21:36:03 +00:00
def set_title(self, title):
"""
Set the title
2010-04-12 07:22:56 +00:00
"""
self.title = title
2010-04-02 23:24:51 +00:00
def set_alternate_title(self, title):
"""
Set the alternate title
2010-04-12 07:22:56 +00:00
"""
self.alternate_title = title
2010-04-01 21:36:03 +00:00
def set_song_number(self, song_number):
"""
2010-04-02 23:24:51 +00:00
Set the song number
2010-04-12 07:22:56 +00:00
"""
self.song_number = song_number
2010-04-01 21:36:03 +00:00
def set_song_book(self, song_book, publisher):
"""
Set the song book name and publisher
2010-04-12 07:22:56 +00:00
"""
self.song_book_name = song_book
self.song_book_pub = publisher
2010-04-01 21:36:03 +00:00
def add_copyright(self, copyright):
"""
Build the copyright field
2010-04-12 07:22:56 +00:00
"""
if self.copyright.find(copyright) >= 0:
return
if self.copyright != u'':
self.copyright += ' '
self.copyright += copyright
def parse_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".
"""
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]
if author2.endswith(u'.'):
author2 = author2[:-1]
if author2:
self.add_author(author2)
def add_author(self, author):
2010-04-01 21:36:03 +00:00
"""
Add an author to the list
2010-04-12 07:22:56 +00:00
"""
if author in self.authors:
return
self.authors.append(author)
def add_verse(self, verse, versetag=None):
2010-04-01 21:36:03 +00:00
"""
Add a verse. This is the whole verse, lines split by \n
2010-04-03 19:17:37 +00:00
Verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the verses/
choruses itself) or None, where it will assume verse
2010-04-01 21:36:03 +00:00
It will also attempt to detect duplicates. In this case it will just
add to the verse order
2010-04-12 07:22:56 +00:00
"""
for (oldversetag, oldverse) in self.verses:
if oldverse.strip() == verse.strip():
self.verse_order_list.append(oldversetag)
2010-04-03 19:17:37 +00:00
return
2010-04-12 07:22:56 +00:00
if versetag == u'V' or not versetag:
self.versecount += 1
versetag = u'V' + unicode(self.versecount)
if versetag.startswith(u'C'):
self.choruscount += 1
if versetag == u'C':
versetag += unicode(self.choruscount)
self.verses.append([versetag, verse.rstrip()])
self.verse_order_list.append(versetag)
if versetag.startswith(u'V') and self.contains_verse(u'C1'):
self.verse_order_list.append(u'C1')
2010-04-01 21:36:03 +00:00
def repeat_verse(self):
"""
Repeat the previous verse in the verse order
2010-04-12 07:22:56 +00:00
"""
self.verse_order_list.append(self.verse_order_list[-1])
2010-04-02 23:24:51 +00:00
def contains_verse(self, versetag):
return versetag in self.verse_order_list
2010-04-12 07:22:56 +00:00
2010-04-01 21:36:03 +00:00
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
2010-04-12 07:22:56 +00:00
"""
if self.title == u'' or len(self.verses) == 0:
return False
else:
return True
2010-04-01 21:36:03 +00:00
def remove_punctuation(self, text):
"""
Remove punctuation from the string for searchable fields
2010-04-02 14:10:10 +00:00
"""
2010-04-12 07:22:56 +00:00
for c in string.punctuation:
2010-04-02 14:10:10 +00:00
text = text.replace(c, u'')
2010-04-12 07:22:56 +00:00
return text
2010-04-01 21:36:03 +00:00
def finish(self):
"""
All fields have been set to this song. Write it away
2010-04-12 07:22:56 +00:00
"""
if len(self.authors) == 0:
self.authors.append(u'Author unknown')
self.commit_song()
2010-04-02 14:10:10 +00:00
#self.print_song()
2010-04-12 07:22:56 +00:00
2010-04-02 14:10:10 +00:00
def commit_song(self):
2010-04-01 21:36:03 +00:00
"""
Write the song and it's fields to disk
2010-04-12 07:22:56 +00:00
"""
song = Song()
song.title = self.title
2010-04-02 23:24:51 +00:00
song.search_title = self.remove_punctuation(self.title) \
2010-04-12 07:22:56 +00:00
+ '@' + self.alternate_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 = self.manager.get_author_by_name(authortext)
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])
self.manager.save_author(author)
song.authors.append(author)
if self.song_book_name:
song_book = self.manager.get_book_by_name(self.song_book_name)
if song_book is None:
song_book = Book()
song_book.name = self.song_book_name
song_book.publisher = self.song_book_pub
self.manager.save_book(song_book)
song.song_book_id = song_book.id
for topictext in self.topics:
topic = self.manager.get_topic_by_name(topictext)
if topic is None:
topic = Topic()
2010-04-02 14:10:10 +00:00
topic.name = topictext
2010-04-12 07:22:56 +00:00
self.manager.save_topic(topic)
2010-04-02 14:10:10 +00:00
song.topics.append(topictext)
2010-04-12 07:22:56 +00:00
self.manager.save_song(song)
def print_song(self):
"""
For debugging
"""
print u'========================================' \
+ u'========================================'
print u'TITLE: ' + self.title
print u'ALT TITLE: ' + self.alternate_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_book_pub:
print u'BOOK PUBLISHER: ' + self.song_book_pub
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
2010-04-01 21:36:03 +00:00