__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