__author__ = "Matt Carlson - matt at cavelli dot org" __version__ = "$Date$" __url__ = "http://www.cavelli.org/plugins/" __description__ = "A book review plugin for pyblosxom" """ To use: add bookreview.py to you load_plugins list in config.py add property "book_db" to your config.py (py["book_db"] = "books.dat") create a book database (example:"books.dat") in your datadir each line of the database is in the form DATE::TITLE::ISBN::AUTHOR::COMMENTS::CATEGORY::KEYWORDS::REVIEW The following templates are used: booklist, bookreview, booksearch* *The template booksearch is only needed if you use the search_books() function Booklist is used to display all books in your book_db Bookreview is used to display a single book The following variables are available: $booklist, $bdate, $title, $isbn, $author, $comments, $category, $keywords, $review What it does: bookreview.py reads a database of book information and displays it in three different ways. 1) On the main page you can list the last 5 books added to the DB by adding the $booklist variable 2) You can see a list of the books in your DB by going to /datadir/booklist.html 3) You can see individual reviews by clicking on the title of a book, or going to /datadir/booklist/?isbn=000000 (where 000000 is the isbn#) bookreview.py was addapted from Will Guaraldi's booklist.py found at http://www.bluesock.org/~willg/pyblosxom/ Bellow is Will's original permission notice: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright 2002-2004 Will Guaraldi bookreview.py Copyright 2005 Matt Carlson """ DATE = 0 NAME = 1 ISBN = 2 AUTHOR = 3 COMMENTS = 4 CATEGORY = 5 KEYWORDS = 6 REVIEW = 7 TRIGGER = "/booklist" import time, cgi, commands from Pyblosxom import tools, entries def title_sort(x, y): articles = ["the", "a", "an"] t1 = x[NAME] t2 = y[NAME] s1 = t1.split() s2 = t2.split() s1_index = 0 s2_index = 0 w1 = s1[s1_index].lower() w2 = s2[s2_index].lower() # Check to see if the title begins with an article for mem in articles: if mem == w1: s1_index += 1 w1 = s1[s1_index].lower() break for mem in articles: if mem == w2: s2_index += 1 w2 = s2[s2_index].lower() break # find the first non matching word in the string same = 1 while same: if cmp(w1,w2) == 0: s1_index += 1 s2_index += 1 w1 = s1[s1_index].lower() w2 = s2[s2_index].lower() else: same = 0 return cmp(w1, w2) def verify_installation(request): config = request.getConfiguration() return 1 def list_one(request, isbn): config = request.getConfiguration() datadir = config["datadir"] book_db = "/" + config['book_db'] grep = commands.getstatusoutput("/usr/bin/egrep -i \"%s\" %s" % (isbn, datadir + book_db)) grep = grep[1] grep = grep.splitlines() booklist = [] for mem in grep: # comments if mem.startswith("#"): continue # blank lines if len(mem.strip()) == 0: continue # continuations if mem.startswith("\t"): booklist[-1][-1] = booklist[-1][-1] + mem continue booklist.append(mem.split("::")) return booklist def populate_list(request): config = request.getConfiguration() datadir = config["datadir"] book_db = "/" + config['book_db'] f = open(datadir + book_db, "r") lines = f.readlines() f.close() booklist = [] for mem in lines: # handle comments if mem.startswith("#"): continue # handle blank lines if len(mem.strip()) == 0: continue # handle continuations if mem.startswith("\t"): mem = " " + mem.rstrip() booklist[-1][-1] = booklist[-1][-1] + mem continue booklist.append(mem.split("::")) return booklist # I want to truncate a string before it is displayed def reduce(tmp_str, str_l): s = tmp_str.split() old_l = 0 new_str = [] for mem in range(len(s)): word = s[mem] w1 = len(word) if (old_l+w1) <= str_l: new_str.append(word) old_l += w1 + 1 else: break if len(new_str) < len(s): new_str.append('...') return ' '.join(new_str) def makelink(tmp_str, url): s = "".join(url) new_str = "" new_str += ('' + tmp_str + '') return new_str class Booklist: def __init__(self, request): self._request = request self._booklist = None def __str__(self): if not self._booklist: self._booklist = populate_list(self._request) listing = self._booklist[:] # only show the last 5 books added to the list listing.reverse() if len(listing) > 5: listing = listing[:5] pyhttp = self._request.getHttp() config = self._request.getConfiguration() output = [] for mem in listing: url = [] url = (config["base_url"] + TRIGGER + "/" + "?isbn=" + mem[ISBN]) name_str = makelink(mem[NAME],url) output.append("%s, by %s
%s

" % (name_str, mem[AUTHOR], reduce(mem[COMMENTS], 80))) output.append('more...
') return "\n".join(output) def generate_entry(request, book): """ Takes a bunch of variables and generates an entry out of it. It creates a timestamp so that conditionalhttp can handle it without getting all fussy. """ entry = entries.base.EntryBase(request) config = request.getConfiguration() data = request.getData() url = [] url.append(config["base_url"] + TRIGGER + "/" + "?isbn=" + book[ISBN]) name_str = makelink(book[NAME],url) entry['title'] = name_str entry['filename'] = "booklist." + book[NAME] entry['file_path'] = "booklist" entry._id = "booklist" + "::" + book[NAME] entry["absolute_path"] = TRIGGER entry["file_path"] = TRIGGER[1:] + "/" + book[ISBN] entry["fn"] = book[ISBN] entry['isbn'] = book[ISBN] entry['author'] = book[AUTHOR] entry['bdate'] = book[DATE] entry['comments'] = book[COMMENTS] entry['category'] = book[CATEGORY] entry['keywords'] = book[KEYWORDS] entry['review'] = book[REVIEW] # not sure how to do this better.... if book[ISBN]: entry['img_isbn'] = 'http://images.amazon.com/images/P/' + book[ISBN] + '.01.TZZZZZZZ.jpg' else: entry['img_isbn'] = '' if data['detail_book'] == 1: entry["template_name"] = "bookreview" elif data['s_book'] == 1: entry["template_name"] = "booksearch" else: entry["template_name"] = "booklist" entry.setTime(time.localtime()) entry.setData(book[COMMENTS]) return entry # search_books can be used to search the book db for a given string (kword) # if you have already built an entry list before you call search_books # you can send that entry and have it added to the returned entrylist # # it adds the template "booksearch" # # Example... # Adding search_books() to wbggrep.py will include your books db in your search # # At the end of cb_filelist() in wbggrep.py replace # # return [entry] # # with: # # entrylist= [] # bookreview_plugin = plugin_utils.get_plugin_by_name("bookreview") # entrylist = bookreview_plugin.search_books(request, query, entry) # # remember to add the following line to the wbggrep.py imports: # # from Pyblosxom import plugin_utils def search_books(request, kword, prev_entry): config = request.getConfiguration() datadir = config["datadir"] book_db = "/" + config['book_db'] data = request.getData() data['s_book'] = 1 grep = commands.getstatusoutput("/usr/bin/egrep -i \"%s\" %s" % (kword, datadir + book_db)) grep = grep[1] grep = grep.splitlines() booklist = [] for mem in grep: # comments if mem.startswith("#"): continue # blank lines if len(mem.strip()) == 0: continue # continuations if mem.startswith("\t"): booklist[-1][-1] = booklist[-1][-1] + mem continue booklist.append(mem.split("::")) entrylist = [] entrylist.append(prev_entry) for mem in booklist: mem[ISBN] = mem[ISBN].strip() entrylist.append(generate_entry(request, mem)) return entrylist def cb_prepare(args): request = args["request"] data = request.getData() data["booklist"] = Booklist(request) INIT_KEY = "booklist_static_file_initiated" def cb_date_head(args): request = args["request"] data = request.getData() if data.has_key(INIT_KEY): args["template"] = "" return args def b_staticrender_filelist(args): request = args["request"] filelist = args["filelist"] flavours = args["flavours"] for f in flavours: filelist.append((TRIGGER + "/index." + f, "")) def cb_pathinfo(args): request = args['request'] data = request.getData() pyhttp = request.getHttp() qstr = pyhttp.get('QUERY_STRING', None) if qstr == None: return None data['s_book'] = 0 data['detail_book'] = 0 parsed_qs = cgi.parse_qs(qstr) if parsed_qs.has_key('isbn'): data['detail_book'] = 1 return None def cb_filelist(args): request = args["request"] pyhttp = request.getHttp() data = request.getData() config = request.getConfiguration() if not pyhttp["PATH_INFO"].startswith(TRIGGER): return qstr = pyhttp.get('QUERY_STRING', None) parsed_qs = cgi.parse_qs(qstr) data[INIT_KEY] = 1 if data['detail_book'] == 1: qstr = pyhttp.get('QUERY_STRING', None) parsed_qs = cgi.parse_qs(qstr) isbn = parsed_qs['isbn'][0] booklist = list_one(request, isbn) data["blog_title"] = config.get("blog_title", "") + " - bookreview" else: booklist = populate_list(request)[:] data["blog_title"] = config.get("blog_title", "") + " - booklist" booklist.sort(title_sort) entrylist = [] for mem in booklist: mem[ISBN] = mem[ISBN].strip() entrylist.append(generate_entry(request, mem)) # Make sure we only include the allowed number of entries max_ent = config.get('num_entries') if max_ent > 0: if len(entrylist) > max_ent: entrylist = entrylist[:max_ent] return entrylist