tag:blogger.com,1999:blog-72739308057986219442024-03-13T03:59:21.000-07:00python, gtk etc.Danielhttp://www.blogger.com/profile/02523346239384252054noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-7273930805798621944.post-74776916302899212962013-01-12T07:10:00.001-08:002013-01-12T07:16:08.420-08:00Emailing books directly from calibre content server to kindleThere are a few guides around to setting up a headless calibre server however there were a few things that I felt were missing from these guides:<br />
<br />
<br />
<ul>
<li>A way to browse the content server and email books directly to my kindle</li>
<li>A way to add new books to the calibre database and update the metadata</li>
</ul>
<h3>
</h3>
<h3>
Emailing books directly from content server to kindle</h3>
<div>
If you're like me you prefer browsing the calibre content server on your computer, rather than on your kindle. While calibre doesn't allow us to email directly from the content server, with a little work you can make this possible. </div>
<div>
<br /></div>
<div>
You'll need to install a webserver (I used lighttpd) to run the following script, it will need to be installed on the same host as the calibre-server.</div>
<div>
<br /></div>
<div>
Save the following script emailbook.py in a place that can be executed by your webserver. Edit the variables at the top (note that calibre-smtp requires your email password to work, I suggest setting up an email address just for sending books):</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#!/usr/bin/env python</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import re</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import cgi</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import cgitb; cgitb.enable() # for troubleshooting</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import sqlite3</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import shutil</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import os.path</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import subprocess</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import os</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">from pipes import quote</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">###Edit these variables for your own system</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">calibre_dir = "/mnt/calibredrive/calibre"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">calibre_db = os.path.join(calibre_dir, "metadata.db")</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">server_email = "your_email@gmail.com"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">password = "Your email password"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">form = cgi.FieldStorage()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">book_id = cgi.escape(form.getvalue("book_id", ""))</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">email = cgi.escape(form.getvalue("email", ""))</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">id = cgi.escape(form.getvalue("id", ""))</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">if book_id != "":</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> db = sqlite3.Connection(calibre_db)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cursor = db.cursor()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cursor.execute("""select * from books where id=?""", (book_id,))</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> book = cursor.fetchone()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> shutil.copyfile(os.path.join(calibre_dir, book[9], "cover.jpg"), "../cover.jpg")</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">else:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> book = None</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#print "Content-type: text/html"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">print """</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><html></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><link rel="stylesheet" href="../style.css" type="text/css" /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><head><title>Email book to kindle</title></head></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><body></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><div id="wrapper"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><div id="header"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><div id="navigation"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><ul><li><a href="http://calibre.zapto.org" target="_blank">Calibre Server</a></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></li></ul></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></div></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><h1> Email book to Kindle </h1></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></div></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><div id="content"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><form method="post" action="emailbook.py"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><p></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><table></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <tr><td>Book ID:</td></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><td><input type="text" name="book_id" value="%s" /></td></tr></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <tr><td>Email:</td><td><input type="text" name="email" value='%s'/></td></tr><tr><td></td><td><input type="submit" width=20px></td></tr></table></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></p></form></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">""" % (id, email)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">if book != None:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if re.match("[^@]+@[^@]+\.[^@]+", email):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> for files in os.listdir(os.path.join(calibre_dir, book[9])):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if files.endswith(".mobi"):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> attachment = quote(os.path.join(calibre_dir, book[9], files))</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> break</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> subprocess.Popen("""calibre-smtp %s %s "book" --attachment %s -r smtp.gmail.com -u %s --port 587 -e TLS -p %s""" %(server_email, email, attachment, server_email, password), shell=True, stdout=open(os.devnull, "w+", 0), stderr = subprocess.STDOUT).pid</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> print """</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <p><b>%s</b> by <b>%s</b> has been queued for delivery to %s</p><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><p /><center><img src="../cover.jpg" /></center>""" % (book[1], book[6], email)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> else:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> print """Invalid email entered"""</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">else:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if book_id != "":</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> print """<p> %s is an invalid book id</p>""" % book_id</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">print """</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></body></html>"""</span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Next we need to edit the html template that calibre uses to generate the webpages for the content server. On my install they were located in <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">/usr/share/calibre/content_server/browse/</span></div>
<div>
Open up <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">summary.html</span>. I removed the <span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;">{get_button}</span> </span>section and replaced it with a link pointing to our emailbook.py script like so:</div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><a href="http://your-website/cgi-bin/emailbook.py?id={id}" target="_blank">Email</a></span><br />
<div>
You can also edit the details.html if you want to create an email link there also.</div>
<div>
<br /></div>
<div>
If you restart the calibre-server you should notice that all the Get buttons have now turned into hyperlinks. Clicking on them should send you to your emailbook script, then just fill in an email address and it will be processed.</div>
<div>
<br /></div>
<div>
For a working example you can visit my <a href="http://calibre.zapto.org/">calibre server</a> which I have running on a raspberry pi.</div>
Danielhttp://www.blogger.com/profile/02523346239384252054noreply@blogger.com0tag:blogger.com,1999:blog-7273930805798621944.post-85976918190168245882009-07-04T05:09:00.000-07:002009-07-04T05:49:25.739-07:00cross platform popup notifications in gtk<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AwHT3I0ROxM/Sk9PFSIcoeI/AAAAAAAAET0/AG4MhlEJ-Co/s1600-h/popupnotify.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 200px;" src="http://3.bp.blogspot.com/_AwHT3I0ROxM/Sk9PFSIcoeI/AAAAAAAAET0/AG4MhlEJ-Co/s320/popupnotify.png" alt="" id="BLOGGER_PHOTO_ID_5354585434152018402" border="0" /></a><br />Recently I've been building a cross platform microblogging system in python with gtk. I was used to using py-notify on the linux platform to give the user popup notifications, however this would obviously not work on windows. I experiemented with the balloon notifications that windows has, but felt they were a bit limiting (no way to add images easily, and to be frank, interacting with the win32api was giving me suicidal tendencies.<br /><br />I've created a simple class, gtkPopupNotify to deal with these things and it's available at <a href="http://github.com/woodenbrick/gtkPopupNotify/tree/master">github</a>. Using it is simple:<br /><span style="font-family:courier new;">import gtkPopupNotify</span> <span style="font-family:courier new;"><br />notifier = gtk.PopupNotify.NotificationStack(timeout=6)</span> <span style="font-family:courier new;">notifier.new_popup(title="Sample popup", message="This is a popup", image="exclamation.png")</span><br /><br />Colours, positioning etc. can all be set via the object properties and will affect all popups created afterwards, eg.<br /><br /><span style="font-family:courier new;">notifier.bg_color = gtk.gdk.Color("green")<br /><br /><span style="font-family:georgia;">Current problems:</span> <span style="font-family:georgia;">Not sure how to check for panel placement so the popup doesn't cover a users panel. On many systems I could use:<br /><br /></span>notifier.edge_offset_y = 30<br /><br /><span style="font-family:georgia;">but obviously this isn't very portable. Suggestions welcome!<br /><br /><br /></span><br /></span>Danielhttp://www.blogger.com/profile/02523346239384252054noreply@blogger.com0