diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 433018c23..41e547800 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -47,26 +47,13 @@ class Renderer(object): Initialise the renderer. """ self._rect = None - self._debug = False - self._display_shadow_size_footer = 0 - self._display_outline_size_footer = 0 self.theme_name = None self._theme = None self._bg_image_filename = None self.frame = None - self.frame_opaque = None self.bg_frame = None self.bg_image = None - def set_debug(self, debug): - """ - Set the debug mode of the renderer. - - ``debug`` - The debug mode. - """ - self._debug = debug - def set_theme(self, theme): """ Set the theme to be used. @@ -159,7 +146,7 @@ class Renderer(object): doc = QtGui.QTextDocument() doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height())) df = doc.defaultFont() - df.setPixelSize(self._theme.font_main_proportion) + df.setPointSize(self._theme.font_main_proportion) df.setFamily(self._theme.font_main_name) main_weight = 50 if self._theme.font_main_weight == u'Bold': @@ -188,7 +175,7 @@ class Renderer(object): # Text too long so gone to next mage if layout.pageCount() != 1: formatted.append(shell % old_html_text) - temp_text = line + temp_text = line + line_end old_html_text = temp_text formatted.append(shell % old_html_text) log.debug(u'format_slide - End') diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index 9caabdc69..6be26bd82 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -93,6 +93,7 @@ class RenderManager(object): """ self.global_theme = global_theme self.theme_level = theme_level + self.themedata = None def set_service_theme(self, service_theme): """ @@ -102,6 +103,7 @@ class RenderManager(object): The service-level theme to be set. """ self.service_theme = service_theme + self.themedata = None def set_override_theme(self, theme, overrideLevels=False): """ @@ -111,6 +113,10 @@ class RenderManager(object): ``theme`` The name of the song-level theme. None means the service item wants to use the given value. + + ``overrideLevels`` + Used to force the theme data passed in to be used. + """ log.debug(u'set override theme to %s', theme) theme_level = self.theme_level @@ -137,6 +143,7 @@ class RenderManager(object): if self.theme != self.renderer.theme_name or self.themedata is None \ or overrideLevels: log.debug(u'theme is now %s', self.theme) + # Force the theme to be the one passed in. if overrideLevels: self.themedata = theme else: diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 4f2ea6df6..868399f83 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -322,9 +322,6 @@ class MainDisplay(DisplayWidget): # Make display show up if in single screen mode if self.isLive: self.setVisible(True) - # save preview for debugging - if log.isEnabledFor(logging.DEBUG): - preview.save(u'temp.png', u'png') return preview def buildHtml(self, serviceItem): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f2961b717..c7d3c497f 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -574,7 +574,7 @@ class ServiceManager(QtGui.QWidget): * An osd which is a pickle of the service items * All image, presentation and video files needed to run the service. """ - log.debug(u'onSaveService') + log.debug(u'onSaveService %s' % quick) if not quick or self.isNew: filename = QtGui.QFileDialog.getSaveFileName(self, translate('OpenLP.ServiceManager', 'Save Service'), @@ -755,6 +755,7 @@ class ServiceManager(QtGui.QWidget): """ Set the theme for the current service """ + log.debug(u'onThemeComboBoxSelected') self.service_theme = unicode(self.themeComboBox.currentText()) self.parent.RenderManager.set_service_theme(self.service_theme) QtCore.QSettings().setValue( @@ -767,6 +768,7 @@ class ServiceManager(QtGui.QWidget): The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state. """ + log.debug(u'themeChange') if self.parent.RenderManager.theme_level == ThemeLevel.Global: self.toolbar.actions[u'ThemeLabel'].setVisible(False) self.toolbar.actions[u'ThemeWidget'].setVisible(False) @@ -779,6 +781,7 @@ class ServiceManager(QtGui.QWidget): Rebuild the service list as things have changed and a repaint is the easiest way to do this. """ + log.debug(u'regenerateServiceItems') # force reset of renderer as theme data has changed self.parent.RenderManager.themedata = None if self.serviceItems: @@ -800,6 +803,7 @@ class ServiceManager(QtGui.QWidget): ``item`` Service Item to be added """ + log.debug(u'addServiceItem') sitem = self.findServiceItem()[0] item.render() if replace: diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 7c0ba6b2b..cc981059c 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -51,9 +51,9 @@ class CSVBible(BibleDB): if u'booksfile' not in kwargs: raise KeyError(u'You have to supply a file to import books from.') self.booksfile = kwargs[u'booksfile'] - if u'versesfile' not in kwargs: + if u'versefile' not in kwargs: raise KeyError(u'You have to supply a file to import verses from.') - self.versesfile = kwargs[u'versesfile'] + self.versesfile = kwargs[u'versefile'] QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index ab38b5f83..e7850c65c 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -47,7 +47,6 @@ class BibleListView(BaseListWithDnD): self.parent().onListViewResize(event.size().width(), event.size().width()) - class BibleMediaItem(MediaManagerItem): """ This is the custom media manager item for Bibles. @@ -466,19 +465,27 @@ class BibleMediaItem(MediaManagerItem): def generateSlideData(self, service_item, item=None): """ - Generates and formats the slides for the service item. + Generates and formats the slides for the service item as well as the + service item's title. """ log.debug(u'generating slide data') items = self.listView.selectedIndexes() if len(items) == 0: return False + has_dual_bible = False bible_text = u'' old_chapter = u'' raw_footer = [] raw_slides = [] - service_item.add_capability(ItemCapabilities.AllowsPreview) - service_item.add_capability(ItemCapabilities.AllowsLoop) - service_item.add_capability(ItemCapabilities.AllowsAdditions) + for item in items: + bitem = self.listView.item(item.row()) + reference = bitem.data(QtCore.Qt.UserRole) + if isinstance(reference, QtCore.QVariant): + reference = reference.toPyObject() + dual_bible = self._decodeQtObject(reference, 'dual_bible') + if dual_bible: + has_dual_bible = True + break # Let's loop through the main lot, and assemble our verses. for item in items: bitem = self.listView.item(item.row()) @@ -491,7 +498,7 @@ class BibleMediaItem(MediaManagerItem): bible = self._decodeQtObject(reference, 'bible') version = self._decodeQtObject(reference, 'version') copyright = self._decodeQtObject(reference, 'copyright') - #permission = self._decodeQtObject(reference, 'permission') + permission = self._decodeQtObject(reference, 'permission') text = self._decodeQtObject(reference, 'text') dual_bible = self._decodeQtObject(reference, 'dual_bible') if dual_bible: @@ -499,70 +506,57 @@ class BibleMediaItem(MediaManagerItem): 'dual_version') dual_copyright = self._decodeQtObject(reference, 'dual_copyright') - #dual_permission = self._decodeQtObject(reference, - # 'dual_permission') + dual_permission = self._decodeQtObject(reference, + 'dual_permission') dual_text = self._decodeQtObject(reference, 'dual_text') - if self.parent.settings_tab.display_style == 1: - verse_text = self.formatVerse(old_chapter, chapter, verse, - u'{su}(', u'){/su}') - elif self.parent.settings_tab.display_style == 2: - verse_text = self.formatVerse(old_chapter, chapter, verse, - u'{su}{', u'}{/su}') - elif self.parent.settings_tab.display_style == 3: - verse_text = self.formatVerse(old_chapter, chapter, verse, - u'{su}[', u']{/su}') - else: - verse_text = self.formatVerse(old_chapter, chapter, verse, - u'{su}', u'{/su}') - old_chapter = chapter - footer = u'%s (%s %s)' % (book, version, copyright) - # If not found add to footer + verse_text = self.formatVerse(old_chapter, chapter, verse) + footer = u'%s (%s %s %s)' % (book, version, copyright, permission) if footer not in raw_footer: raw_footer.append(footer) - if dual_bible: - footer = u'%s (%s %s)' % (book, dual_version, - dual_copyright) - # If not found add second version and copyright to footer. - if footer not in raw_footer: - raw_footer.append(footer) - bible_text = u'%s %s \n\n %s %s' % (verse_text, text, - verse_text, dual_text) - raw_slides.append(bible_text) - bible_text = u'' - else: - # If we are 'Verse Per Line' then force a new line. - if self.parent.settings_tab.layout_style == 1: - text = text + u'\n' - else: - # split the line but do not replace line breaks in renderer - service_item.add_capability(ItemCapabilities.NoLineBreaks) - text = text + u'\n' - bible_text = u'%s %s %s' % (bible_text, verse_text, text) - # If we are 'Verse Per Slide' then create a new slide. - if self.parent.settings_tab.layout_style == 0: - raw_slides.append(bible_text) - bible_text = u'' - # If we are not 'Verse Per Slide' we have to make sure, that we - # add more verses. - else: - if item.row() < len(items) - 1: - bitem = items[item.row() + 1] - reference = bitem.data(QtCore.Qt.UserRole) - if isinstance(reference, QtCore.QVariant): - reference = reference.toPyObject() - bible_new = self._decodeQtObject(reference, 'bible') - dual_bible_new = self._decodeQtObject(reference, - 'dual_bible') - if dual_bible_new: - raw_slides.append(bible_text) - bible_text = u'' - elif bible != bible_new: - raw_slides.append(bible_text) - bible_text = u'' - else: + if has_dual_bible: + if dual_bible: + footer = u'%s (%s %s %s)' % (book, dual_version, + dual_copyright, dual_permission) + if footer not in raw_footer: + raw_footer.append(footer) + # If there is an old bible_text we have to add it. + if bible_text: raw_slides.append(bible_text) bible_text = u'' - # service item title + bible_text = u'%s %s\n\n%s %s' % (verse_text, text, + verse_text, dual_text) + raw_slides.append(bible_text) + bible_text = u'' + elif self.parent.settings_tab.layout_style == 0: + bible_text = u'%s %s' % (verse_text, text) + raw_slides.append(bible_text) + bible_text = u'' + else: + bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) + # If we are 'Verse Per Slide' then create a new slide. + elif self.parent.settings_tab.layout_style == 0: + bible_text = u'%s %s' % (verse_text, text) + raw_slides.append(bible_text) + bible_text = u'' + # If we are 'Verse Per Line' then force a new line. + elif self.parent.settings_tab.layout_style == 1: + bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) + # We have to be 'Continuous'. + else: + bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) + old_chapter = chapter + # If there are no more items we check whether we have to add bible_text. + if bible_text: + raw_slides.append(bible_text) + bible_text = u'' + # Service Item: Capabilities + if self.parent.settings_tab.layout_style == 2 and not has_dual_bible: + # split the line but do not replace line breaks in renderer + service_item.add_capability(ItemCapabilities.NoLineBreaks) + service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) + service_item.add_capability(ItemCapabilities.AllowsAdditions) + # Service Item: Title if not service_item.title: if dual_bible: service_item.title = u'%s (%s, %s) %s' % (book, version, @@ -573,7 +567,7 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'etc')) == -1: service_item.title = u'%s, %s' % (service_item.title, translate('BiblesPlugin.MediaItem', 'etc')) - # item theme + # Service Item: Theme if len(self.parent.settings_tab.bible_theme) == 0: service_item.theme = None else: @@ -587,14 +581,20 @@ class BibleMediaItem(MediaManagerItem): service_item.raw_footer = raw_footer return True - def formatVerse(self, old_chapter, chapter, verse, opening, closing): - verse_text = opening - if old_chapter != chapter: - verse_text += chapter + u':' - elif not self.parent.settings_tab.show_new_chapters: - verse_text += chapter + u':' - verse_text += verse - verse_text += closing + def formatVerse(self, old_chapter, chapter, verse): + if not self.parent.settings_tab.show_new_chapters or \ + old_chapter != chapter: + verse_text = chapter + u':' + verse + else: + verse_text = verse + if self.parent.settings_tab.display_style == 1: + verse_text = u'{su}(' + verse_text + u'){/su}' + elif self.parent.settings_tab.display_style == 2: + verse_text = u'{su}{' + verse_text + u'}{/su}' + elif self.parent.settings_tab.display_style == 3: + verse_text = u'{su}[' + verse_text + u']{/su}' + else: + verse_text = u'{su}' + verse_text + u'{/su}' return verse_text def reloadBibles(self): @@ -639,14 +639,14 @@ class BibleMediaItem(MediaManagerItem): for i in range(int(range_from), int(range_to) + 1): combo.addItem(unicode(i)) - def displayResults(self, bible, dual_bible=None): + def displayResults(self, bible, dual_bible=u''): """ Displays the search results in the media manager. All data needed for further action is saved for/in each row. """ version = self.parent.manager.get_meta_data(bible, u'Version') copyright = self.parent.manager.get_meta_data(bible, u'Copyright') - #permission = self.parent.manager.get_meta_data(bible, u'Permissions') + permission = self.parent.manager.get_meta_data(bible, u'Permissions') if dual_bible: dual_version = self.parent.manager.get_meta_data(dual_bible, u'Version') @@ -654,43 +654,41 @@ class BibleMediaItem(MediaManagerItem): u'Copyright') dual_permission = self.parent.manager.get_meta_data(dual_bible, u'Permissions') - if dual_permission: - dual_permission = dual_permission.value - else: + if not dual_permission: dual_permission = u'' # We count the number of rows which are maybe already present. start_count = self.listView.count() for count, verse in enumerate(self.search_results): if dual_bible: vdict = { - 'book':QtCore.QVariant(verse.book.name), - 'chapter':QtCore.QVariant(verse.chapter), - 'verse':QtCore.QVariant(verse.verse), - 'bible':QtCore.QVariant(bible), - 'version':QtCore.QVariant(version.value), - 'copyright':QtCore.QVariant(copyright.value), - #'permission':QtCore.QVariant(permission.value), - 'text':QtCore.QVariant(verse.text), - 'dual_bible':QtCore.QVariant(dual_bible), - 'dual_version':QtCore.QVariant(dual_version.value), - 'dual_copyright':QtCore.QVariant(dual_copyright.value), - #'dual_permission':QtCore.QVariant(dual_permission), - 'dual_text':QtCore.QVariant( + 'book': QtCore.QVariant(verse.book.name), + 'chapter': QtCore.QVariant(verse.chapter), + 'verse': QtCore.QVariant(verse.verse), + 'bible': QtCore.QVariant(bible), + 'version': QtCore.QVariant(version.value), + 'copyright': QtCore.QVariant(copyright.value), + 'permission': QtCore.QVariant(permission.value), + 'text': QtCore.QVariant(verse.text), + 'dual_bible': QtCore.QVariant(dual_bible), + 'dual_version': QtCore.QVariant(dual_version.value), + 'dual_copyright': QtCore.QVariant(dual_copyright.value), + 'dual_permission': QtCore.QVariant(dual_permission.value), + 'dual_text': QtCore.QVariant( self.dual_search_results[count].text) } bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, verse.chapter, verse.verse, version.value, dual_version.value) else: vdict = { - 'book':QtCore.QVariant(verse.book.name), - 'chapter':QtCore.QVariant(verse.chapter), - 'verse':QtCore.QVariant(verse.verse), - 'bible':QtCore.QVariant(bible), - 'version':QtCore.QVariant(version.value), - 'copyright':QtCore.QVariant(copyright.value), - #'permission':QtCore.QVariant(permission.value), - 'text':QtCore.QVariant(verse.text), - 'dual_bible':QtCore.QVariant(dual_bible) + 'book': QtCore.QVariant(verse.book.name), + 'chapter': QtCore.QVariant(verse.chapter), + 'verse': QtCore.QVariant(verse.verse), + 'bible': QtCore.QVariant(bible), + 'version': QtCore.QVariant(version.value), + 'copyright': QtCore.QVariant(copyright.value), + 'permission': QtCore.QVariant(permission.value), + 'text': QtCore.QVariant(verse.text), + 'dual_bible': QtCore.QVariant(dual_bible) } bible_text = u' %s %d:%d (%s)' % (verse.book.name, verse.chapter, verse.verse, version.value) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 6fb6b38a0..f2a59ba81 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -83,6 +83,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): QtCore.QObject.connect(self.wordsOfWorshipRemoveButton, QtCore.SIGNAL(u'clicked()'), self.onWordsOfWorshipRemoveButtonClicked) + QtCore.QObject.connect(self.ccliAddButton, + QtCore.SIGNAL(u'clicked()'), + self.onCCLIAddButtonClicked) + QtCore.QObject.connect(self.ccliRemoveButton, + QtCore.SIGNAL(u'clicked()'), + self.onCCLIRemoveButtonClicked) QtCore.QObject.connect(self.songsOfFellowshipAddButton, QtCore.SIGNAL(u'clicked()'), self.onSongsOfFellowshipAddButtonClicked) @@ -277,6 +283,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): def onWordsOfWorshipRemoveButtonClicked(self): self.removeSelectedItems(self.wordsOfWorshipFileListWidget) + def onCCLIAddButtonClicked(self): + self.getFiles( + translate('SongsPlugin.ImportWizardForm', + 'Select CCLI Files'), + self.ccliFileListWidget + ) + + def onCCLIRemoveButtonClicked(self): + self.removeSelectedItems(self.ccliFileListWidget) + def onSongsOfFellowshipAddButtonClicked(self): self.getFiles( translate('SongsPlugin.ImportWizardForm', diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py new file mode 100755 index 000000000..08bccef79 --- /dev/null +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -0,0 +1,310 @@ +# -*- 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, Meinert Jordan, Andreas Preikschat, Christian # +# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # +# Carsten Tinggaard, Frode Woldsund, Derek Scotney # +# --------------------------------------------------------------------------- # +# 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 logging +import os +import chardet +import codecs + +from songimport import SongImport + +log = logging.getLogger(__name__) + +class CCLIFileImportError(Exception): + pass + +class CCLIFileImport(SongImport): + """ + The :class:`CCLIFileImport` class provides OpenLP with the + ability to import CCLI SongSelect song files in both .txt and + .usr formats. See http://www.ccli.com + """ + + def __init__(self, manager, **kwargs): + """ + Initialise the import. + + ``manager`` + The song manager for the running OpenLP installation. + ``filenames`` + The files to be imported. + """ + SongImport.__init__(self, manager) + if u'filenames' in kwargs: + self.filenames = kwargs[u'filenames'] + log.debug(self.filenames) + else: + raise KeyError(u'Keyword argument "filenames" not supplied.') + + def do_import(self): + """ + Import either a .usr or a .txt SongSelect file + """ + log.debug(u'Starting CCLI File Import') + song_total = len(self.filenames) + self.import_wizard.importProgressBar.setMaximum(song_total) + song_count = 1 + for filename in self.filenames: + self.import_wizard.incrementProgressBar( + u'Importing song %s of %s' % (song_count, song_total)) + filename = unicode(filename) + log.debug(u'Importing CCLI File: %s', filename) + lines = [] + if os.path.isfile(filename): + detect_file = open(filename, u'r') + details = chardet.detect(detect_file.read(2048)) + detect_file.close() + infile = codecs.open(filename, u'r', details['encoding']) + lines = infile.readlines() + ext = os.path.splitext(filename)[1] + if ext.lower() == ".usr": + log.info(u'SongSelect .usr format file found %s: ' , filename) + self.do_import_usr_file(lines) + elif ext.lower() == ".txt": + log.info(u'SongSelect .txt format file found %s: ', filename) + self.do_import_txt_file(lines) + else: + log.info(u'Extension %s is not valid', filename) + pass + song_count += 1 + if self.stop_import_flag: + return False + return True + + def do_import_usr_file(self, textList): + """ + The :method:`do_import_usr_file` method provides OpenLP + with the ability to import CCLI SongSelect songs in + *USR* file format + + ``textList`` + An array of strings containing the usr file content. + + **SongSelect .usr file format** + ``[File]`` + USR file format first line + ``Type=`` + Indicates the file type + e.g. *Type=SongSelect Import File* + ``Version=3.0`` + File format version + ``[S A2672885]`` + Contains the CCLI Song number e.g. *2672885* + ``Title=`` + Contains the song title (e.g. *Title=Above All*) + ``Author=`` + Contains a | delimited list of the song authors + e.g. *Author=LeBlanc, Lenny | Baloche, Paul* + ``Copyright=`` + Contains a | delimited list of the song copyrights + e.g. Copyright=1999 Integrity's Hosanna! Music | + LenSongs Publishing (Verwaltet von Gerth Medien + Musikverlag) + ``Admin=`` + Contains the song administrator + e.g. *Admin=Gerth Medien Musikverlag* + ``Themes=`` + Contains a /t delimited list of the song themes + e.g. *Themes=Cross/tKingship/tMajesty/tRedeemer* + ``Keys=`` + Contains the keys in which the music is played?? + e.g. *Keys=A* + ``Fields=`` + Contains a list of the songs fields in order /t delimited + e.g. *Fields=Vers 1/tVers 2/tChorus 1/tAndere 1* + ``Words=`` + Contains the songs various lyrics in order as shown by the + *Fields* description + e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF] + """ + log.debug(u'USR file text: %s', textList) + lyrics = [] + self.set_defaults() + for line in textList: + if line.startswith(u'Title='): + song_name = line[6:].strip() + elif line.startswith(u'Author='): + song_author = line[7:].strip() + elif line.startswith(u'Copyright='): + song_copyright = line[10:].strip() + elif line.startswith(u'[S A'): + song_ccli = line[4:-3].strip() + elif line.startswith(u'Fields='): + #Fields contain single line indicating verse, chorus, etc, + #/t delimited, same as with words field. store seperately + #and process at end. + song_fields = line[7:].strip() + elif line.startswith(u'Words='): + song_words = line[6:].strip() + #Unhandled usr keywords:Type,Version,Admin,Themes,Keys + #Process Fields and words sections + field_list = song_fields.split(u'/t') + words_list = song_words.split(u'/t') + for counter in range(0, len(field_list)): + if field_list[counter].startswith(u'Ver'): + verse_type = u'V' + elif field_list[counter].startswith(u'Ch'): + verse_type = u'C' + elif field_list[counter].startswith(u'Br'): + verse_type = u'B' + else: #Other + verse_type = u'O' + verse_text = unicode(words_list[counter]) + verse_text = verse_text.replace("/n", "\n") + if len(verse_text) > 0: + self.add_verse(verse_text, verse_type); + #Handle multiple authors + author_list = song_author.split(u'/') + if len(author_list) < 2: + author_list = song_author.split(u'|') + for author in author_list: + seperated = author.split(u',') + self.add_author(seperated[1].strip() + " " + seperated[0].strip()) + self.title = song_name + self.copyright = song_copyright + self.ccli_number = song_ccli + self.finish() + + def do_import_txt_file(self, textList): + """ + The :method:`do_import_txt_file` method provides OpenLP + with the ability to import CCLI SongSelect songs in + *TXT* file format + + ``textList`` + An array of strings containing the txt file content. + + **SongSelect .txt file format** + + ``Song Title`` + Contains the song title + + + + ``Title of following verse/chorus and number`` + e.g. Verse 1, Chorus 1 + + ``Verse/Chorus lyrics`` + + + + + + ``Title of next verse/chorus (repeats)`` + + ``Verse/Chorus lyrics`` + + + + + + ``Song CCLI Number`` + e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885) + ``Song Copyright`` + e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing + ``Song Authors`` + e.g. Lenny LeBlanc | Paul Baloche + ``Licencing info`` + e.g. For use solely with the SongSelect Terms of Use. + All rights Reserved. www.ccli.com + ``CCLI Licence number of user`` + e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 + """ + log.debug(u'TXT file text: %s', textList) + self.set_defaults() + line_number = 0 + verse_text = u'' + song_comments = u'' + song_copyright = u''; + verse_start = False + for line in textList: + clean_line = line.strip() + if not clean_line: + if line_number==0: + continue + elif verse_start: + if verse_text: + self.add_verse(verse_text, verse_type) + verse_text = '' + verse_start = False + else: + #line_number=0, song title + if line_number==0: + song_name = clean_line + line_number += 1 + #line_number=1, verses + elif line_number==1: + #line_number=1, ccli number, first line after verses + if clean_line.startswith(u'CCLI'): + line_number += 1 + ccli_parts = clean_line.split(' ') + song_ccli = ccli_parts[len(ccli_parts)-1] + elif not verse_start: + # We have the verse descriptor + verse_desc_parts = clean_line.split(' ') + if len(verse_desc_parts) == 2: + if verse_desc_parts[0].startswith(u'Ver'): + verse_type = u'V' + elif verse_desc_parts[0].startswith(u'Ch'): + verse_type = u'C' + elif verse_desc_parts[0].startswith(u'Br'): + verse_type = u'B' + else: + verse_type = u'O' + verse_number = verse_desc_parts[1] + else: + verse_type = u'O' + verse_number = 1 + verse_start = True + else: + # We have verse content or the start of the + # last part. Add l so as to keep the CRLF + verse_text = verse_text + line + else: + #line_number=2, copyright + if line_number==2: + line_number += 1 + song_copyright = clean_line + #n=3, authors + elif line_number==3: + line_number += 1 + song_author = clean_line + #line_number=4, comments lines before last line + elif (line_number==4) and (not clean_line.startswith(u'CCL')): + song_comments = song_comments + clean_line + # split on known separators + author_list = song_author.split(u'/') + if len(author_list) < 2: + author_list = song_author.split(u'|') + #Clean spaces before and after author names + for author_name in author_list: + self.add_author(author_name.strip()) + self.title = song_name + self.copyright = song_copyright + self.ccli_number = song_ccli + self.comments = song_comments + self.finish() + diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index ae18f4389..5801ea44a 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport try: from sofimport import SofImport from oooimport import OooImport + from cclifileimport import CCLIFileImport from wowimport import WowImport except ImportError: pass @@ -68,6 +69,8 @@ class SongFormat(object): return WowImport elif format == SongFormat.Generic: return OooImport + elif format == SongFormat.CCLI: + return CCLIFileImport # else: return None diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index dd83c679d..bf5079c8c 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -43,12 +43,6 @@ class SongImport(QtCore.QObject): whether the authors etc already exist and add them or refer to them as necessary """ - - COPYRIGHT_STRING = unicode(translate( - 'SongsPlugin.SongImport', 'copyright')) - COPYRIGHT_SYMBOL = unicode(translate( - 'SongsPlugin.SongImport', '\xa9')) - def __init__(self, manager): """ Initialise and create defaults for properties @@ -58,11 +52,11 @@ class SongImport(QtCore.QObject): """ self.manager = manager self.stop_import_flag = False + self.set_defaults() QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) - self.setDefaults() - - def setDefaults(self): + + def set_defaults(self): self.title = u'' self.song_number = u'' self.alternate_title = u'' @@ -78,6 +72,10 @@ class SongImport(QtCore.QObject): self.verses = [] self.versecount = 0 self.choruscount = 0 + self.copyright_string = unicode(translate( + 'SongsPlugin.SongImport', 'copyright')) + self.copyright_symbol = unicode(translate( + 'SongsPlugin.SongImport', '\xa9')) def stop_import(self): """ @@ -163,8 +161,7 @@ class SongImport(QtCore.QObject): 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 + 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','): @@ -241,7 +238,7 @@ class SongImport(QtCore.QObject): """ All fields have been set to this song. Write it away """ - if len(self.authors) == 0: + if not self.authors: self.authors.append(u'Author unknown') self.commit_song()