diff --git a/openlp/plugins/songs/lib/songDBimpl.py b/openlp/plugins/songs/lib/songDBimpl.py new file mode 100644 index 000000000..a99440cd0 --- /dev/null +++ b/openlp/plugins/songs/lib/songDBimpl.py @@ -0,0 +1,203 @@ +""" +OpenLP - Open Source Lyrics Projection +Copyright (c) 2008 Raoul Snyman +Portions copyright (c) 2008 Martin Thompson, Tim Bentley + +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, os.path +import sys +import time +import datetime +import logging +import string + +from sqlalchemy import * +from sqlalchemy.sql import select +from sqlalchemy.orm import sessionmaker, mapper + +from openlp.plugins.bibles.lib.biblecommon import BibleCommon +from openlp.core.utils import ConfigHelper + +import logging + +class BibleDBException(Exception): + pass +class BibleInvalidDatabaseError(Exception): + pass + +metadata = MetaData() +#authors = Table('authors', metadata, autoload=True) + +class SongDBImpl(BibleCommon): + global log + log=logging.getLogger("SongDBImpl") + log.info("SongDBImpl loaded") + def __init__(self, songpath , suffix, btype = 'sqlite'): + # Connect to database + self.songfile = os.path.join(songpath, "songs."+suffix) + log.debug( "Load Song on path %s", self.songfile) + if btype == 'sqlite': + self.db = create_engine("sqlite:///"+self.songfile) + elif btype == 'mysql': + self.db = create_engine("mysql://tim:@192.168.0.100:3306/openlp_rsv_bible") + else: + raise BibleInvalidDatabaseError("Database not mysql or sqlite") + self.db.echo = True + #self.metadata = metaData() + metadata.bind = self.db + metadata.bind.echo = False + self.Session = sessionmaker() + self.Session.configure(bind=self.db) + authors = Table('authors', metadata, autoload=True) + settings = Table('settings', metadata, autoload=True) + songauthors = Table('songauthors', metadata, autoload=True) + songs = Table('songs', metadata, autoload=True) + + def create_tables(self): + log.debug( "createTables") + if os.path.exists(self.biblefile): # delete bible file and set it up again + os.remove(self.biblefile) + meta_table.create() + testament_table.create() + book_table.create() + verse_table.create() + self.save_meta("dbversion", "2") + self._loadTestaments() + + def add_verse(self, bookid, chap, verse, text): + log.debug( "add_verse %s,%s,%s,%s", bookid, chap, verse, text) + metadata.bind.echo = False + session = self.Session() + versemeta = Verse(book_id=int(bookid), chapter=int(chap), verse=int(verse), text=(text)) + session.add(versemeta) + session.commit() + + def create_chapter(self, bookid, chap, textlist): + log.debug( "create_chapter %s,%s,%s", bookid, chap, textlist) + metadata.bind.echo = False + session = self.Session() + #s = text (""" select id FROM book where book.name == :b """) + #data = self.db.execute(s, b=bookname).fetchone() + #id = data[0] # id is first record in list. + #log.debug( "id = " , id + for v , t in textlist.iteritems(): + versemeta = Verse(book_id=bookid, chapter=int(chap), verse=int(v), text=(t)) + session.add(versemeta) + session.commit() + + def create_book(self, bookid, bookname, bookabbrev): + log.debug( "create_book %s,%s,%s", bookid, bookname, bookabbrev) + metadata.bind.echo = False + session = self.Session() + bookmeta = Book(int(5), bookname, bookabbrev) + session.add(bookmeta) + session.commit() + + def save_meta(self, key, value): + metadata.bind.echo = False + session = self.Session() + bmeta= BibleMeta(key, value) + session.add(bmeta) + session.commit() + + def get_meta(self, key): + s = text (""" select value FROM metadata where key == :k """) + return self.db.execute(s, k=key).fetchone() + + def delete_meta(self, key): + metadata.bind.echo = False + s = text (""" delete FROM meta where key == :k """) + self.db.execute(s, k=key) + + def _load_testaments(self): + log.debug("load_testaments") + metadata.bind.echo = False + session = self.Session() + testmeta = ONTestament(name="Old Testament") + session.add(testmeta) + testmeta = ONTestament(name="New Testament") + session.add(testmeta) + testmeta = ONTestament(name="Apocrypha") + session.add(testmeta) + session.commit() + + def get_bible_books(self): + log.debug( "get_bible_book ") + metadata.bind.echo = False + s = text (""" select name FROM book order by id """) + return self.db.execute(s).fetchall() + + def get_max_bible_book_verses(self, bookname, chapter): + log.debug( "get_max_bible_book_verses %s,%s ", bookname , chapter) + metadata.bind.echo = False + s = text (""" select max(verse.verse) from verse,book where chapter = :c and book_id = book.id and book.name = :b """) + return self.db.execute(s, c=chapter, b=bookname).fetchone() + + def get_max_bible_book_chapter(self, bookname): + log.debug( "get_max_bible_book_chapter %s ", bookname ) + metadata.bind.echo = False + s = text (""" select max(verse.chapter) from verse,book where book_id = book.id and book.name = :b """) + return self.db.execute(s, b=bookname).fetchone() + + def get_bible_book(self, bookname): + log.debug( "get_bible_book %s", bookname) + metadata.bind.echo = False + s = text (""" select name FROM book where book.name == :b """) + return self.db.execute(s, b=bookname).fetchone() + + def get_bible_book_Id(self, bookname): + log.debug( "get_bible_book_id %s", bookname) + metadata.bind.echo = False + s = text (""" select id FROM book where book.name == :b """) + return self.db.execute(s, b=bookname).fetchone() + + def get_bible_chapter(self, bookname, chapter): + log.debug( "get_bible_chapter %s,%s", bookname, chapter ) + metadata.bind.echo = False + s = text (""" select book.name FROM verse,book where verse.book_id == book.id AND verse.chapter == :c and book.name == :b """) + return self.db.execute(s, c=chapter, b=bookname).fetchone() + + def get_bible_text(self, bookname, chapter, sverse, everse): + log.debug( "get_bible_text %s,%s,%s,%s ", bookname, chapter, sverse, everse) + metadata.bind.echo = False + s = text (""" select name,chapter,verse.verse, verse.text FROM verse , book where verse.book_id == book.id AND verse.chapter == :c AND (verse.verse between :v1 and :v2) and book.name == :b """) + return self.db.execute(s, c=chapter, v1=sverse , v2=everse, b=bookname).fetchall() + + def get_song_from_lyrics(self,searchtext): + log.debug( "get_song_from_lyrics %s",searchtext) + metadata.bind.echo = False + searchtext = "%"+searchtext+"%" + s = text (""" SELECT s.songid AS songid, s.songtitle AS songtitle, a.authorname AS authorname FROM songs s OUTER JOIN songauthors sa ON s.songid = sa.songid OUTER JOIN authors a ON sa.authorid = a.authorid WHERE s.lyrics LIKE :t ORDER BY s.songtitle ASC """) + return self.db.execute(s, t=searchtext).fetchall() + + def get_song_from_title(self,searchtext): + log.debug( "get_song_from_title %s",searchtext) + metadata.bind.echo = False + searchtext = "%"+searchtext+"%" + s = text (""" SELECT s.songid AS songid, s.songtitle AS songtitle, a.authorname AS authorname FROM songs s OUTER JOIN songauthors sa ON s.songid = sa.songid OUTER JOIN authors a ON sa.authorid = a.authorid WHERE s.songtitle LIKE :t ORDER BY s.songtitle ASC """) + return self.db.execute(s, t=searchtext).fetchall() + + def get_song_from_author(self,searchtext): + log.debug( "get_song_from_author %s",searchtext) + metadata.bind.echo = False + searchtext = "%"+searchtext+"%" + s = text (""" SELECT s.songid AS songid, s.songtitle AS songtitle, a.authorname AS authorname FROM songs s OUTER JOIN songauthors sa ON s.songid = sa.songid OUTER JOIN authors a ON sa.authorid = a.authorid WHERE a.authorname LIKE :t ORDER BY s.songtitle ASC """) + return self.db.execute(s, t=searchtext).fetchall() + + + def dump_songs(self): + log.debug( ".........Dumping Songs Database") + log.debug( "...............................Books ") + s = text (""" select * FROM authors """) + log.debug( self.db.execute(s).fetchall()) diff --git a/openlp/plugins/songs/lib/songmanager.py b/openlp/plugins/songs/lib/songmanager.py new file mode 100644 index 000000000..319d374d1 --- /dev/null +++ b/openlp/plugins/songs/lib/songmanager.py @@ -0,0 +1,262 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 +""" +OpenLP - Open Source Lyrics Projection +Copyright (c) 2008 Raoul Snyman +Portions copyright (c) 2008 Martin Thompson, Tim Bentley + +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, os.path +import sys + +from songDBimpl import SongDBImpl + + +import logging + +class SongManager(): + global log + log=logging.getLogger("SongManager") + log.info("Song manager loaded") + def __init__(self, config): + """ + Finds all the bibles defined for the system + Creates an Interface Object for each bible containing connection information + Throws Exception if no Bibles are found. + + Init confirms the bible exists and stores the database path. + """ + self.config = config + log.debug( "Song Initialising") + self.bibleDBCache = None + #self.bibleHTTPCache = {} # dict of bible http readers + self.songPath = self.config.get_data_path() + self.songSuffix = self.config.get_config("suffix name", u'olp3') + log.debug("Song Path %s and suffix %s", self.songPath, self.songSuffix ) + self.dialogobject = None + + files = self.config.get_files() + if len(files) > 0: + log.debug("Song File %s", files ) + self.songDBCache = SongDBImpl(self.songPath, self.songSuffix) + + log.debug( "Song Initialised") + + def process_dialog(self, dialogobject): + self.dialogobject = dialogobject + + def register_HTTP_bible(self, biblename, biblesource, mode="lazy", proxyurl=None, proxyid=None, proxypass=None): + """ + Return a list of bibles from a given URL. + The selected Bible can then be registered and LazyLoaded into a database + """ + log.debug( "register_HTTP_bible %s,%s,%s,%s,%s", biblename, biblesource, proxyurl, proxyid, proxypass, mode) + if self._is_new_bible(biblename): + nbible = BibleDBImpl(self.biblePath, biblename, self.bibleSuffix) # Create new Bible + nbible.createTables() # Create Database + self.bibleDBCache[biblename] = nbible + + nhttp = BibleHTTPImpl() + nhttp.setBibleSource(biblesource) + self.bibleHTTPCache[biblename] = nhttp + nbible.save_meta("WEB", biblesource) # register a lazy loading interest + if proxyurl != None: + nbible.save_meta("proxy", proxyurl) # store the proxy URL + nhttp.setProxy(proxyurl) + if proxyid != None: + nbible.save_meta("proxyid", proxyid) # store the proxy userid + if proxypass != None: + nbible.save_meta("proxypass", proxypass) # store the proxy password + + + def register_CVS_file_bible(self, biblename, booksfile, versefile): + """ + Method to load a bible from a set of files into a database. + If the database exists it is deleted and the database is reloaded + from scratch. + """ + if self._is_new_bible(biblename): + nbible = BibleDBImpl(self.biblePath, biblename, self.bibleSuffix) # Create new Bible + nbible.createTables() # Create Database + self.bibleDBCache[biblename] = nbible # cache the database for use later + bcsv = BibleCSVImpl(nbible) # create the loader and pass in the database + bcsv.load_data(booksfile, versefile) + + def register_OSIS_file_bible(self, biblename, osisfile): + """ + Method to load a bible from a osis xml file extracted from Sword bible viewer. + If the database exists it is deleted and the database is reloaded + from scratch. + """ + log.debug( "register_OSIS_file_bible %s , %s", biblename, osisfile) + if self._is_new_bible(biblename): + nbible = BibleDBImpl(self.biblePath, biblename, self.bibleSuffix) # Create new Bible + nbible.createTables() # Create Database + self.bibleDBCache[biblename] = nbible # cache the database for use later + bcsv = BibleOSISImpl(self.biblePath, nbible) # create the loader and pass in the database + bcsv.loadData(osisfile, self.dialogobject) + + +# def loadBible(self,biblename): +# """ +# Downloads all the books of the bible +# and loads it into the database +# """ +# log.debug( "loadBible %s", biblename) +# bookabbrev = "" +# for bookname in self.listOfBooks: +# cptrs = self.booksChapters[ self.booksOfBible[bookname]] +# log.debug( "book and chapter %s %s", bookname , self.booksChapters[ self.booksOfBible[bookname]] ) +# for chptr in range(1 , int(cptrs)): # loop through all the chapters in book +# c = self.bibleDBCache[biblename].getBibleChapter(bookname, chptr) # check to see if book/chapter exists +# log.debug( "got chapter %s", c) +# if not c: +# bookid = self.booksOfBible[bookname] # convert to id ie Genesis --> 1 Revelation --> 73 +# log.debug( "missing %s,%s", bookname, chptr) +# self._loadBook(biblename,bookid, bookname, bookabbrev) +# self._loadChapter(biblename,bookid, bookname, chptr) + + def get_bibles(self, mode="full"): + """ + Returns a list of Books of the bible + """ + r=[] + for b , o in self.bibleDBCache.iteritems(): + if mode != "full": + print self.bibleHTTPCache[b] + r.append(b) + return r + + def get_bible_books(self,bible): + """ + Returns a list of the books of the bible from the database + """ + log.debug("get_bible_books %s", bible) + return self.bibleDBCache[bible].get_bible_books() + + def get_book_chapter_count(self, bible, book): + """ + Returns the number of Chapters for a given book + """ + log.debug( "get_book_chapter_count %s,%s", bible, book) + return self.bibleDBCache[bible].get_max_bible_book_chapter(book) + + def get_book_verse_count(self, bible, book, chapter): + """ + Returns all the number of verses for a given + book and chapterMaxBibleBookVerses + """ + log.debug( "get_book_verse_count %s,%s,%s", bible, book, chapter) + return self.bibleDBCache[bible].get_max_bible_book_verses(book, chapter) + + def get_verse_from_text(self, bible, versetext): + """ + Returns all the number of verses for a given + book and chapterMaxBibleBookVerses + """ + log.debug( "get_verses_from_text %s,%s", bible, versetext) + return self.bibleDBCache[bible].get_verses_from_text(versetext) + + def save_meta_data(self, bible, version, copyright, permissions): + """ + Saves the bibles meta data + """ + log.debug( "save_meta %s,%s, %s,%s", bible, version, copyright, permissions) + self.bibleDBCache[bible].save_meta("Version", version) + self.bibleDBCache[bible].save_meta("Copyright", copyright) + self.bibleDBCache[bible].save_meta("Permissins", permissions) + + def get_meta_data(self, bible, key): + """ + Returns the meta data for a given key + """ + log.debug( "get_meta %s,%s", bible, key) + self.bibleDBCache[bible].get_meta(key) + + def get_verse_text(self, bible, bookname, schapter, echapter, sverse, everse = 0 ): + """ + Returns a list of verses for a given Book, Chapter and ranges of verses. + If the end verse(everse) is less then the start verse(sverse) + then only one verse is returned + bible - Which bible to use. + Rest can be guessed at ! + """ + text = [] + #log.debug( self.bibleDBCache) + #log.debug( self.bibleHTTPCache) + log.debug( "get_verse_text %s,%s,%s,%s,%s,%s", bible,bookname, schapter,echapter, sverse, everse) +# bookid = self.booksOfBible[bookname] # convert to id ie Genesis --> 1 Revelation --> 73 +# # SORT OUT BOOKNAME BOOK ID. +# # NAME COMES IN TO ID AND BACK TO NAME ? +# c = self.bibleDBCache[bible].getBibleChapter(bookname, chapter) # check to see if book/chapter exists +# bookabbrev = "" +# log.debug( "Bible Chapter %s", c ) +# if not c: +# self._loadBook(bible,bookid, bookname, bookabbrev) +# self._loadChapter(bible, bookid,bookname, chapter) + if schapter == echapter: + text = self.bibleDBCache[bible].get_bible_text(bookname, schapter, sverse, everse) + else: + for i in range (schapter, echapter + 1): + if i == schapter: + start = sverse + end = self.get_book_verse_count(bible, bookname,i )[0] + elif i == echapter: + start = 1 + end = everse + else: + start = 1 + end = self.get_book_verse_count(bible, bookname,i )[0] + + txt = self.bibleDBCache[bible].get_bible_text(bookname, i, start, end) + text.extend(txt) + return text + + def _load_book(self, bible, bookid, bookname, bookabbrev): + log.debug( "load_book %s,%s,%s,%s", bible, bookid, bookname, bookabbrev) + cl = self.bibleDBCache[bible].get_bible_book(bookname) + log.debug( "get bible book %s" , cl) + if not cl : + self.bibleDBCache[bible].create_book(bookid, bookname, bookabbrev) + + def _loadChapter(self, bible, bookid, bookname, chapter): + log.debug( "load_chapter %s,%s,%s,%s", bible, bookid,bookname, chapter) + try : + chaptlist = self.bibleHTTPCache[bible].get_bible_chapter(bible, bookid,bookname, chapter) + self.bibleDBCache[bible].create_chapter(bookname, chapter, chaptlist) + except : + log.error("Errow thrown %s", sys.exc_info()[1]) + + def _is_new_bible(self, name): + """ + Check cache to see if new bible + """ + for b , o in self.bibleDBCache.iteritems(): + log.debug( b ) + if b == name : + return False + return True + + def get_song_from_title(self,searchtext): + return self.songDBCache.get_song_from_title(searchtext) + + def get_song_from_lyrics(self,searchtext): + return self.songDBCache.get_song_from_lyrics(searchtext) + + def get_song_from_author(self,searchtext): + return self.songDBCache.get_song_from_author(searchtext) + + def dump_songs(self): + self.songDBCache.dump_songs() diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 24597c911..a64cb3117 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -107,6 +107,7 @@ class SongsPlugin(Plugin): self.MediaManagerItem.PageLayout.addWidget(self.SongWidget) self.SongListView = QtGui.QTableWidget() self.SongListView.setColumnCount(2) + self.SongListView.setHorizontalHeaderLabels(QtCore.QStringList(["Song Name","Author"])) self.SongListView.setGeometry(QtCore.QRect(10, 100, 256, 591)) self.SongListView.setObjectName("listView") self.MediaManagerItem.PageLayout.addWidget(self.SongListView) @@ -182,10 +183,19 @@ class SongsPlugin(Plugin): def onSearchTextButton(self): searchtext = str(self.SearchTextEdit.displayText() ) - if str(self.SearchTypeComboBox.currentText=="Titles"): + ct = self.SearchTypeComboBox.currentText() + print ct , str(ct) + if self.SearchTypeComboBox.currentText()=="Titles": + print "Titles" self.searchresults = self.songmanager.get_song_from_title(searchtext) - elif str(self.SearchTypeComboBox.currentText=="Lyrics"): - self.searchresults = self.songmanager.get_song_from_lyrics(searchtext) + elif self.SearchTypeComboBox.currentText()=="Lyrics": + print "Lyrics" + self.searchresults = self.songmanager.get_song_from_lyrics(searchtext) + elif self.SearchTypeComboBox.currentText()=="Authors": + print "Authors" + self.searchresults = self.songmanager.get_song_from_author(searchtext) + else: + print "missed ", ct self._display_results() def onSongNewClick(self): @@ -220,9 +230,13 @@ class SongsPlugin(Plugin): def _display_results(self): self.SongListView.clear() # clear the results + self.SongListView.setHorizontalHeaderLabels(QtCore.QStringList(["Song Name","Author"])) self.SongListView.setRowCount(0) - for id, txt in self.searchresults: + for id, txt, name in self.searchresults: c = self.SongListView.rowCount() self.SongListView.setRowCount(c+1) twi = QtGui.QTableWidgetItem(str(txt)) - self.SongListView.setItem(c , 0, twi) + self.SongListView.setItem(c , 0, twi) + twi = QtGui.QTableWidgetItem(str(name)) + self.SongListView.setItem(c , 1, twi) +