forked from openlp/openlp
Add CCLI file importer to song wizard
bzr-revno: 1002
This commit is contained in:
commit
bb03d313d8
@ -83,6 +83,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
|
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
self.onWordsOfWorshipRemoveButtonClicked)
|
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.QObject.connect(self.songsOfFellowshipAddButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
self.onSongsOfFellowshipAddButtonClicked)
|
self.onSongsOfFellowshipAddButtonClicked)
|
||||||
@ -277,6 +283,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
def onWordsOfWorshipRemoveButtonClicked(self):
|
def onWordsOfWorshipRemoveButtonClicked(self):
|
||||||
self.removeSelectedItems(self.wordsOfWorshipFileListWidget)
|
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):
|
def onSongsOfFellowshipAddButtonClicked(self):
|
||||||
self.getFiles(
|
self.getFiles(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
|
310
openlp/plugins/songs/lib/cclifileimport.py
Executable file
310
openlp/plugins/songs/lib/cclifileimport.py
Executable file
@ -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
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``Title of following verse/chorus and number``
|
||||||
|
e.g. Verse 1, Chorus 1
|
||||||
|
|
||||||
|
``Verse/Chorus lyrics``
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``Title of next verse/chorus (repeats)``
|
||||||
|
|
||||||
|
``Verse/Chorus lyrics``
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``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()
|
||||||
|
|
@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport
|
|||||||
try:
|
try:
|
||||||
from sofimport import SofImport
|
from sofimport import SofImport
|
||||||
from oooimport import OooImport
|
from oooimport import OooImport
|
||||||
|
from cclifileimport import CCLIFileImport
|
||||||
from wowimport import WowImport
|
from wowimport import WowImport
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
@ -68,6 +69,8 @@ class SongFormat(object):
|
|||||||
return WowImport
|
return WowImport
|
||||||
elif format == SongFormat.Generic:
|
elif format == SongFormat.Generic:
|
||||||
return OooImport
|
return OooImport
|
||||||
|
elif format == SongFormat.CCLI:
|
||||||
|
return CCLIFileImport
|
||||||
# else:
|
# else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -43,12 +43,6 @@ class SongImport(QtCore.QObject):
|
|||||||
whether the authors etc already exist and add them or refer to them
|
whether the authors etc already exist and add them or refer to them
|
||||||
as necessary
|
as necessary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COPYRIGHT_STRING = unicode(translate(
|
|
||||||
'SongsPlugin.SongImport', 'copyright'))
|
|
||||||
COPYRIGHT_SYMBOL = unicode(translate(
|
|
||||||
'SongsPlugin.SongImport', '\xa9'))
|
|
||||||
|
|
||||||
def __init__(self, manager):
|
def __init__(self, manager):
|
||||||
"""
|
"""
|
||||||
Initialise and create defaults for properties
|
Initialise and create defaults for properties
|
||||||
@ -58,11 +52,11 @@ class SongImport(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.stop_import_flag = False
|
self.stop_import_flag = False
|
||||||
|
self.set_defaults()
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
|
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
|
||||||
self.setDefaults()
|
|
||||||
|
|
||||||
def setDefaults(self):
|
def set_defaults(self):
|
||||||
self.title = u''
|
self.title = u''
|
||||||
self.song_number = u''
|
self.song_number = u''
|
||||||
self.alternate_title = u''
|
self.alternate_title = u''
|
||||||
@ -78,6 +72,10 @@ class SongImport(QtCore.QObject):
|
|||||||
self.verses = []
|
self.verses = []
|
||||||
self.versecount = 0
|
self.versecount = 0
|
||||||
self.choruscount = 0
|
self.choruscount = 0
|
||||||
|
self.copyright_string = unicode(translate(
|
||||||
|
'SongsPlugin.SongImport', 'copyright'))
|
||||||
|
self.copyright_symbol = unicode(translate(
|
||||||
|
'SongsPlugin.SongImport', '\xa9'))
|
||||||
|
|
||||||
def stop_import(self):
|
def stop_import(self):
|
||||||
"""
|
"""
|
||||||
@ -163,8 +161,7 @@ class SongImport(QtCore.QObject):
|
|||||||
def parse_author(self, text):
|
def parse_author(self, text):
|
||||||
"""
|
"""
|
||||||
Add the author. OpenLP stores them individually so split by 'and', '&'
|
Add the author. OpenLP stores them individually so split by 'and', '&'
|
||||||
and comma.
|
and comma. However need to check for 'Mr and Mrs Smith' and turn it to
|
||||||
However need to check for 'Mr and Mrs Smith' and turn it to
|
|
||||||
'Mr Smith' and 'Mrs Smith'.
|
'Mr Smith' and 'Mrs Smith'.
|
||||||
"""
|
"""
|
||||||
for author in text.split(u','):
|
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
|
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.authors.append(u'Author unknown')
|
||||||
self.commit_song()
|
self.commit_song()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user