<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Troll-Range &#187; Python</title>
	<atom:link href="http://blog.trollgod.org.uk/category/development/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.trollgod.org.uk</link>
	<description>Ghworg&#039;s wibblings and geek projects.</description>
	<lastBuildDate>Mon, 26 Apr 2010 19:31:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>OAuthcalypse</title>
		<link>http://blog.trollgod.org.uk/2010/04/oauthcalypse/</link>
		<comments>http://blog.trollgod.org.uk/2010/04/oauthcalypse/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 19:31:11 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[webapp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=396</guid>
		<description><![CDATA[<p>So, I have a twitter/status.net app that I use to consolidate all the micro-blogs I&#8217;m on and produce a single timeline in a sidebar of my news page. It was originally written as a python plugin for pyblosxom, which runs the rest of the site. It turns out that this causes huge delays in <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2010/04/oauthcalypse/">OAuthcalypse</a></span>]]></description>
			<content:encoded><![CDATA[<p>So, I have a twitter/status.net <a href="http://blog.trollgod.org.uk/projects/twixm/">app</a> that I use to consolidate all the micro-blogs I&#8217;m on and produce a single timeline in a sidebar of my news page.  It was originally written as a python plugin for <a href="http://pyblosxom.bluesock.org/">pyblosxom</a>, which runs the rest of the site.  It turns out that this causes huge delays in producing the page though and I eventually rewrote it in javascript.</p>
<p>This is really nice because it all runs client-side and can take its sweet time to pull in the feeds without affecting the rendering of the bulk of the page.  It grabs the friend feeds so it needs to login to the various sites, and it uses http basic auth for this.  Nice and simple.</p>
<p>I&#8217;ve just learned of the coming <a href="http://countdowntooauth.com/">OAuthcalypse</a> though, where the basic auth method is going to be disabled, and this presents me with a quandary.  I need to update my app to use OAuth, there are three ways I could do this:</p>
<p><strong>1) Implement OAuth in javascript.</strong>  This is a really bad idea.  OAuth uses a secret key, and as javascript has to be sent to the browser in plain text it wouldn&#8217;t remain secret for long.</p>
<p><strong>2) Move the app back server side and implement OAuth in python.</strong>  Again this is a bad idea, I moved it client side for a <em>reason</em>, and putting it back server side would give me unacceptable performance.</p>
<p><strong>3) A hybrid approach where the OAuth is done server side, and the requests themselves remain javascript on the client.</strong>  Having had a brief look at how OAuth works I <em>think</em> this might be possible.  It will still slow things down, but it might be good enough.  It&#8217;s going to be a pain in the arse to implement though.</p>
<p>Well, at least I know what I&#8217;m doing with my Bank Holiday.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2010/04/oauthcalypse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Poor mans offsite backup</title>
		<link>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/</link>
		<comments>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/#comments</comments>
		<pubDate>Sat, 02 May 2009 07:00:34 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[gmail]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=192</guid>
		<description><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail. Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p> <p>This is the script I used to send the <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/">Poor mans offsite backup</a></span>]]></description>
			<content:encoded><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail.  Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p>
<p>This is the script I used to send the files:</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span><br />
<span class="kw1">import</span> <span class="kw3">getpass</span><br />
<span class="kw1">import</span> <span class="kw3">optparse</span><br />
<span class="kw1">import</span> <span class="kw3">smtplib</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p><span class="kw1">from</span> <span class="kw3">email</span> <span class="kw1">import</span> Encoders<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEBase</span> <span class="kw1">import</span> MIMEBase<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEMultipart</span> <span class="kw1">import</span> MIMEMultipart</p>
<p>
opts = <span class="kw3">optparse</span>.<span class="me1">OptionParser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-u&#8217;</span>, <span class="st0">&#8216;&#8211;username&#8217;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-p&#8217;</span>, <span class="st0">&#8216;&#8211;password&#8217;</span><span class="br0">&#41;</span><br />
<span class="br0">&#40;</span>options, args<span class="br0">&#41;</span> = opts.<span class="me1">parse_args</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span> &lt; <span class="nu0">1</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Usage: send_file_to_gmail.py [-u user] [-p pass] filename&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span></p>
<p><span class="kw1">if</span> options.<span class="me1">username</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> = <span class="kw2">raw_input</span><span class="br0">&#40;</span><span class="st0">&quot;Username: &quot;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">password</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">password</span> = <span class="kw3">getpass</span>.<span class="kw3">getpass</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">username</span><span class="br0">&#91;</span><span class="kw2">len</span><span class="br0">&#40;</span>options.<span class="me1">username</span><span class="br0">&#41;</span><span class="nu0">-10</span>:<span class="br0">&#93;</span> != <span class="st0">&quot;@gmail.com&quot;</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> += <span class="st0">&quot;@gmail.com&quot;</span></p>
<p>
msg = MIMEMultipart<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;Subject&#8217;</span><span class="br0">&#93;</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;From&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;To&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span></p>
<p>msg.<span class="me1">preamble</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg.<span class="me1">epilogue</span> = <span class="st0">&quot; &quot;</span></p>
<p>fp = <span class="kw2">open</span><span class="br0">&#40;</span>args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, <span class="st0">&quot;rb&quot;</span><span class="br0">&#41;</span><br />
atfile = MIMEBase<span class="br0">&#40;</span><span class="st0">&quot;application&quot;</span>, <span class="st0">&quot;octet-stream&quot;</span><span class="br0">&#41;</span><br />
atfile.<span class="me1">set_payload</span><span class="br0">&#40;</span>fp.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
fp.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
Encoders.<span class="me1">encode_base64</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span><br />
atfile.<span class="me1">add_header</span><span class="br0">&#40;</span><span class="st0">&quot;Content-Disposition&quot;</span>, <span class="st0">&quot;attachment&quot;</span>, filename=args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
msg.<span class="me1">attach</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span></p>
<p>s = <span class="kw3">smtplib</span>.<span class="me1">SMTP</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="co1">#s.connect(&quot;localhost&quot;, &quot;8025&quot;)</span><br />
s.<span class="me1">connect</span><span class="br0">&#40;</span><span class="st0">&quot;smtp.gmail.com&quot;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">starttls</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">login</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">password</span><span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;Sending %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
s.<span class="me1">sendmail</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">username</span>, msg.<span class="me1">as_string</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
s.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp;</div>
<p>The above code is made available under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a> license.</p>
<p>* While I am writing this the Dreamhost backup space I use has been down for about two weeks (it came back briefly a couple of days ago but is back down again now).  I can&#8217;t complain too much as it is a free extra they throw in with the hosting package but I may have to restart my gmail sending if this keeps up.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convert files to UTF-8</title>
		<link>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/#comments</comments>
		<pubDate>Thu, 16 Apr 2009 05:00:54 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[utf8]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=178</guid>
		<description><![CDATA[<p>I occasionally come across text files with weird squiggles or numbers in them were there should be characters. Usually it&#8217;s accented characters, but in extreme cases I&#8217;ve seen it happen with speech marks.</p> <p>The problem of course is that the files are not ASCII, and text files don&#8217;t store what character set they were <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/">Convert files to UTF-8</a></span>]]></description>
			<content:encoded><![CDATA[<p>I occasionally come across text files with weird squiggles or numbers in them were there should be characters.  Usually it&#8217;s accented characters, but in extreme cases I&#8217;ve seen it happen with speech marks.</p>
<p>The problem of course is that the files are not ASCII, and text files don&#8217;t store what character set they were created with.  So if the set my system happens to use doesn&#8217;t match the one the file uses then the result is screwed up letters.</p>
<p>To solve this I created a little python script that converts the file into using the UTF-8 character set as that is nice and universal.  You can specify what codec the input is in with the -c option, if you don&#8217;t bother then it assumes the Windows 1252 codepage as that is usually what it is in my experience.  There is also a force option for when the conversion comes across characters that don&#8217;t match the input codec but you want it to convert anyway.</p>
<p>I thought about making it autodetect the codec of the input file, but it is a lot of work for little benefit.  The current code works in 99% of cases for me.</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span></p>
<p><span class="kw1">import</span> <span class="kw3">codecs</span><br />
<span class="kw1">import</span> <span class="kw3">optparse</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p><span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span> &lt; <span class="nu0">2</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&#8216;convert_cp1252_to_UTF-8.py [-f] $filename&#8217;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span></p>
<p>opts = <span class="kw3">optparse</span>.<span class="me1">OptionParser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="co1"># &#8216;help&#8217;, &#8216;config=&#8217;, &#8216;logfile=&#8217;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-f&#8217;</span>, <span class="st0">&#8216;&#8211;force&#8217;</span>, action=<span class="st0">&#8216;store_true&#8217;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-c&#8217;</span>, <span class="st0">&#8216;&#8211;codec&#8217;</span>, default=<span class="st0">&#8216;cp1252&#8242;</span><span class="br0">&#41;</span><br />
<span class="br0">&#40;</span>parsedOpts, args<span class="br0">&#41;</span> = opts.<span class="me1">parse_args</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
filename = args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span></p>
<p><span class="kw1">try</span>:<br />
&nbsp; &nbsp; <span class="kw1">if</span> parsedOpts.<span class="me1">force</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; textfile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename, <span class="st0">&#8216;r&#8217;</span>, encoding=parsedOpts.<span class="me1">codec</span>, errors=<span class="st0">&#8216;ignore&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; textfile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename, <span class="st0">&#8216;r&#8217;</span>, encoding=parsedOpts.<span class="me1">codec</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; utffile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename+<span class="st0">&#8216;.utf-8&#8242;</span>, <span class="st0">&#8216;w&#8217;</span>, encoding=<span class="st0">&#8216;utf-8&#8242;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; utffile.<span class="me1">write</span><span class="br0">&#40;</span>textfile.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="kw1">except</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&#8216;Error converting to UTF-8, source file probably doesn&#8217;</span>t use cp1252<span class="st0">&#8216;<br />
</span></div>
<p>The above code is made available under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a> license.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter to XMPP (Jabber)</title>
		<link>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/</link>
		<comments>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 21:23:50 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[xmpp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=118</guid>
		<description><![CDATA[<p>The other day I noticed that irssi (the IRC client I use) had a XMPP plugin. It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p> <p>For identi.ca this was a doddle, since laconica supports XMPP natively. Twitter however <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/">Twitter to XMPP (Jabber)</a></span>]]></description>
			<content:encoded><![CDATA[<p>The other day I noticed that <a href="http://irssi.org/">irssi</a> (the <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">IRC</a> client I use) had a <a href="http://cybione.org/~irssi-xmpp/">XMPP plugin</a>.  It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p>
<p>For <a href="http://identi.ca/ghworg">identi.ca</a> this was a doddle, since <a href="http://laconi.ca/">laconica</a> supports <a href="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">XMPP</a> natively.  <a href="http://twitter.com/Ghworg">Twitter</a> however was a problem.  I believe twitter used to support XMPP but they pulled that feature for who knows what reason.</p>
<p>There are a couple of apps that will provided a twitter->XMPP gateway for you.  I looked at <a href="http://dustin.github.com/twitterspy/">twitterspy</a>, but it sounded like a pain to install.  So at first I tried <a href="https://www.tweet.im/">tweet.im</a>, which worked after a fashion.  It got the tweets into irssi, but it did it in some weird way so that irssi didn&#8217;t realise new messages had come in and hence it didn&#8217;t indicate there was activity when I was in a different irssi window.</p>
<p>At this point the little voice in my head that is the bane of my life started saying &#8220;You know, you could probably write your own gateway app.  How hard could it be?&#8221;.  Like a fool I listened to this voice, but for once it didn&#8217;t turn out disastrously.  A few hours later I had a functioning (one-way) twitter->XMPP app, written in python.</p>
<p>I&#8217;ve since learned that twitterspy has been rewritten in python and would have been a doddle to install.  Not only that but there is a public instance of it I could have used.  Still, I&#8217;m not immune to <a href="http://en.wikipedia.org/wiki/Not_Invented_Here">NIH</a> syndrome and having my own app to do it is nice.  If you want a twitter->XMPP gateway of your own though I suggest you try <a href="http://dustin.github.com/twitterspy/">twitterspy</a> first as it is much more capable (and mature) than my noddy little script.</p>
<p>But if you are interested, and because I like to boast about my tiny little achievements, here is twixm (I&#8217;ll give it its own page when I get round to it, but till then it is going to live in this blog post).</p>
<div class="dean_ch" style="white-space: nowrap;">
<p><span class="co1">#!/usr/bin/python -u</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is free software: you can redistribute it and/or modify</span><br />
<span class="co1"># it under the terms of the GNU General Public License as published by</span><br />
<span class="co1"># the Free Software Foundation, either version 2 of the License, or</span><br />
<span class="co1"># (at your option) any later version.</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is distributed in the hope that it will be useful,</span><br />
<span class="co1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br />
<span class="co1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. &nbsp;See the</span><br />
<span class="co1"># GNU General Public License for more details.</span><br />
<span class="co1">#</span><br />
<span class="co1"># You should have received a copy of the GNU General Public License</span><br />
<span class="co1"># along with this program. &nbsp;If not, see &lt;http://www.gnu.org/licenses/&gt;.</span><br />
<span class="co1"># </span></p>
<p>__author__ = <span class="st0">&quot;Ghworg&quot;</span><br />
__version__ = <span class="st0">&quot;1.0&quot;</span><br />
__description__ = <span class="st0">&quot;Twitter to XMPP gateway&quot;</span></p>
<p>
<span class="kw1">import</span> <span class="kw3">logging</span>, <span class="kw3">os</span>, <span class="kw3">signal</span>, <span class="kw3">sys</span>, <span class="kw3">threading</span>, <span class="kw3">time</span>, <span class="kw3">urllib</span></p>
<p><span class="kw1">import</span> simplejson</p>
<p><span class="kw1">try</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> iniparse.<span class="me1">compat</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span><br />
<span class="kw1">except</span> <span class="kw2">ImportError</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> <span class="kw3">ConfigParser</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span></p>
<p><span class="kw1">from</span> pyxmpp.<span class="me1">jid</span> <span class="kw1">import</span> JID<br />
<span class="kw1">from</span> pyxmpp.<span class="me1">jabber</span>.<span class="me1">simple</span> <span class="kw1">import</span> send_message</p>
<p>
<span class="kw1">class</span> WebApiOpener<span class="br0">&#40;</span><span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; Provides a way for HTTP Basic authentication to take place without<br />
&nbsp; &nbsp; prompting the user for a username and password like FancyURLopener<br />
&nbsp; &nbsp; would.<br />
&nbsp; &nbsp; &quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>, username, password<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>,<span class="br0">&#123;</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">username</span> = username<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">password</span> = password<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> prompt_user_passwd<span class="br0">&#40;</span><span class="kw2">self</span>, host, realm<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle Basic Auth automatically.&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw2">self</span>.<span class="me1">username</span>, <span class="kw2">self</span>.<span class="me1">password</span><span class="br0">&#41;</span></p>
<p>
<span class="kw1">class</span> CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="kw3">ConfigParser</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Case Sensitive version of ConfigParser&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">ConfigParser</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> optionxform<span class="br0">&#40;</span><span class="kw2">self</span>, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Make keys case-sensitive&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">str</span><span class="br0">&#40;</span>option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> getAndType<span class="br0">&#40;</span><span class="kw2">self</span>, section, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Try to guess variable type and convert to type before returning&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; rawVal = <span class="kw2">self</span>.<span class="me1">get</span><span class="br0">&#40;</span>section, option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> c <span class="kw1">in</span> rawVal:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> c.<span class="me1">isdigit</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> c != <span class="st0">&#8216;.&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> isInt:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">int</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elif</span> isFloat:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">float</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> rawVal</p>
<p>
<span class="kw1">def</span> msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Send a message to Jabber (XMPP)&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> jid.<span class="kw3">resource</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>jid.<span class="me1">node</span>, jid.<span class="me1">domain</span>, <span class="st0">&#8216;send_message&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; recpt = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Sending to XMPP &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; send_message<span class="br0">&#40;</span>jid, config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span>, recpt, msg<span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> getTweets<span class="br0">&#40;</span><span class="kw3">site</span>, maxTweets=<span class="nu0">1</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Read in a list of tweets made since the last check&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">in</span> cache:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?since_id=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?count=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, maxTweets<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; opener = WebApiOpener<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span class="kw1">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Requesting %s&#8217;</span> % url<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; webPage = opener.<span class="kw2">open</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; jsonData = simplejson.<span class="me1">load</span><span class="br0">&#40;</span>webPage<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="st0">&#8216;error&#8217;</span> <span class="kw1">in</span> jsonData<span class="br0">&#41;</span> <span class="kw1">and</span> <span class="br0">&#40;</span>jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span> != <span class="st0">&#8221;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Error from server %s: %s&#8217;</span> % <span class="br0">&#40;</span>url, jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jsonData = <span class="kw2">None</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">IOError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">ValueError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; maxID = <span class="nu0">0</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> tweet <span class="kw1">in</span> jsonData:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span> &gt; maxID:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msg = <span class="st0">&#8216;%s (%s): %s&#8217;</span> % <span class="br0">&#40;</span>tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;user&#8217;</span><span class="br0">&#93;</span><span class="br0">&#91;</span>u<span class="st0">&#8216;screen_name&#8217;</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;text&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Read tweet &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> maxID</p>
<p><span class="kw1">def</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Thread&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="kw2">True</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = getTweets<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">not</span> <span class="kw1">in</span> cache<span class="br0">&#41;</span> <span class="kw1">or</span> <span class="br0">&#40;</span>maxID &gt; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span> = maxID</p>
<p><span class="kw1">def</span> readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Load config settings&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; config = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; cfgfile = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">expanduser</span><span class="br0">&#40;</span><span class="st0">&#8216;~&#8217;</span><span class="br0">&#41;</span>, <span class="st0">&#8216;.twixmrc&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span> = CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span>.<span class="me1">read</span><span class="br0">&#40;</span>cfgfile<span class="br0">&#41;</span><br />
&nbsp; &nbsp; settings = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> section <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">sections</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;XMPP&#8217;</span> == section:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> optname <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">options</span><span class="br0">&#40;</span>section<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span>optname<span class="br0">&#93;</span> = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, optname<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteName = section<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUrl = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;URL&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUser = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Username&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sitePass = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Password&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">site</span> = <span class="br0">&#40;</span>siteName, siteUrl, siteUser, sitePass<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;site&#8217;</span> <span class="kw1">not</span> <span class="kw1">in</span> config:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span> = <span class="nu0">60.0</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="co1"># !!! Check for missing config settings and bail out</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP ID = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP Pass = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Cycle Time = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Site: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>URL: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>User: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>Pass: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> config<br />
&nbsp; &nbsp; &nbsp; &nbsp; </p>
<p><span class="kw1">def</span> setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Setup python logging to stdout&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; log = <span class="kw3">logging</span>.<span class="me1">getLogger</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; logformat = <span class="st0">&#8216;%(asctime)s %(levelname)s %(message)s&#8217;</span><br />
&nbsp; &nbsp; dateformat = <span class="st0">&#8216;%Y-%m-%d %H:%M:%S&#8217;</span><br />
&nbsp; &nbsp; frmttr = <span class="kw3">logging</span>.<span class="me1">Formatter</span><span class="br0">&#40;</span>logformat, dateformat<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#if options.logfile:</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr = logging.FileHandler(options.logfile)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr.setFormatter(frmttr)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;log.addHandler(fhdlr)</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">sys</span>.<span class="me1">stdin</span>.<span class="me1">isatty</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr = <span class="kw3">logging</span>.<span class="me1">StreamHandler</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">stdout</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr.<span class="me1">setFormatter</span><span class="br0">&#40;</span>frmttr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log.<span class="me1">addHandler</span><span class="br0">&#40;</span>shdlr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#log.setLevel(logging.DEBUG)</span><br />
&nbsp; &nbsp; log.<span class="me1">setLevel</span><span class="br0">&#40;</span><span class="kw3">logging</span>.<span class="me1">INFO</span><span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> handler<span class="br0">&#40;</span>signum, frame<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle various termination signals gracefully&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Signal handler called with signal %d&#8217;</span> % signum<span class="br0">&#41;</span><br />
&nbsp; &nbsp; quitSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>
<span class="co1">###############################################################################</span><br />
<span class="co1"># Main</span><br />
<span class="co1">###############################################################################</span></p>
<p><span class="co1"># Set the signal handlers</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGTERM</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGQUIT</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGINT</span>, handler<span class="br0">&#41;</span></p>
<p>setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>config = readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
cache = <span class="br0">&#123;</span><span class="br0">&#125;</span></p>
<p>
quitSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
startSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>runThread = <span class="kw3">threading</span>.<span class="me1">Thread</span><span class="br0">&#40;</span>target=run<span class="br0">&#41;</span><br />
runThread.<span class="me1">start</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p><span class="kw1">while</span> <span class="kw2">False</span> == quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; count = <span class="nu0">0.0</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> count &lt; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; quitSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="nu0">0.5</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; count += <span class="nu0">0.5</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><br />
<span class="kw3">logging</span>.<span class="me1">info</span><span class="br0">&#40;</span><span class="st0">&#8216;Exiting&#8217;</span><span class="br0">&#41;</span></p>
<p>&nbsp;</p></div>
<p>Update 2009-11-25:  I have created a page for <a href="/projects/twixm/">twixm</a> now.  Go there for the latest code and info.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Backup script v2</title>
		<link>http://blog.trollgod.org.uk/2006/02/backup-script-v2/</link>
		<comments>http://blog.trollgod.org.uk/2006/02/backup-script-v2/#comments</comments>
		<pubDate>Sat, 18 Feb 2006 08:21:13 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Admin]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=45</guid>
		<description><![CDATA[<p>I&#8217;ve rewritten my backup script in python (it was in bash) in order to make the old backup handling date-based rather than a simple iteration. So it now renames dirs to daily.1, daily2, weekly1, monthly1 for old backups that are one day, two days, one week, one month old etc.</p> <p>Not being able to <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2006/02/backup-script-v2/">Backup script v2</a></span>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve rewritten my backup script in python (it was in bash) in order to make the old backup handling date-based rather than a simple iteration.  So it now renames dirs to daily.1, daily2, weekly1, monthly1 for old backups that are one day, two days, one week, one month old etc.</p>
<p>Not being able to use external programs as easily means the script is about twice as big, but I guess the fewer external dependencies is a good thing.  I&#8217;m still using ping and rsync binaries, I&#8217;d like to replace the ping with something in pure python but I&#8217;m not going to be reimplementing rsync in python <img src='http://blog.trollgod.org.uk/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<p>There is also now a very nice option handling system, run gkbackup -h to see all the options.  The log output is much better aswell, logging to stdout if running in a terminal and running quietly if not while also logging to a file in both cases if requested.</p>
<p>The new version is <a href="http://blog.trollgod.org.uk/linux/backupscript/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2006/02/backup-script-v2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OPML support for rss2file</title>
		<link>http://blog.trollgod.org.uk/2005/11/opml-support-for-rss2file/</link>
		<comments>http://blog.trollgod.org.uk/2005/11/opml-support-for-rss2file/#comments</comments>
		<pubDate>Tue, 08 Nov 2005 13:46:51 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=34</guid>
		<description><![CDATA[<p>I&#8217;ve added OPML import/export functions to my little aggregator program rss2file. Was quite a bit more awkward than it should be due to the braindeadness of the format. I&#8217;ve no idea whether the import will work beyond the examples I&#8217;ve tried it with, because there are no standard attributes. You basically have to guess <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2005/11/opml-support-for-rss2file/">OPML support for rss2file</a></span>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve added OPML import/export functions to my little aggregator program <a href="http://blog.trollgod.org.uk/projects/rss2file/">rss2file</a>.  Was quite a bit more awkward than it should be due to the braindeadness of the format.  I&#8217;ve no idea whether the import will work beyond the examples I&#8217;ve tried it with, because there are <strong>no standard attributes</strong>.  You basically have to guess what names people are using for things and use those, xmlUrl seems fairly universal but for the rest it&#8217;s pot luck.</p>
<p>Anyway, the basic code is there at least and it shouldn&#8217;t be too hard to add support for the inevitable files that it doesn&#8217;t handle currently.</p>
<p>Oh, and I updated the command line parsing stuff to be a bit more sophisticated.  It should be backwards compatible, but you&#8217;ll be better off using the new format.  Just run &#8220;rss2file -h&#8221; to see the options.</p>
<p><a href="http://blog.trollgod.org.uk/files/rss2file.tar.bz2">Download</a> the new version.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2005/11/opml-support-for-rss2file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Music Player Daemon</title>
		<link>http://blog.trollgod.org.uk/2005/10/music-player-daemon/</link>
		<comments>http://blog.trollgod.org.uk/2005/10/music-player-daemon/#comments</comments>
		<pubDate>Mon, 31 Oct 2005 17:41:17 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=30</guid>
		<description><![CDATA[<p>I have finally been able to ditch the crash-fest that is known as xmms, several times in the past year I&#8217;ve looked for alternatives to it but nothing ever seemed to be able to meet my requirements. It&#8217;s not like I&#8217;m looking for anything esoteric, all I want is</p> ESD output support for mp3, <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2005/10/music-player-daemon/">Music Player Daemon</a></span>]]></description>
			<content:encoded><![CDATA[<p>I have finally been able to ditch the crash-fest that is known as xmms, several times in the past year I&#8217;ve looked for alternatives to it but nothing ever seemed to be able to meet my requirements.  It&#8217;s not like I&#8217;m looking for anything esoteric, all I want is</p>
<ol>
<li>ESD output</li>
<li>support for mp3, ogg, flac and m3u playlists</li>
<li>no KDE dependencies (I use Gnome)</li>
<li>controllable from the keyboard and lirc</li>
<li>and most important of all STABLE</li>
</ol>
<p>Yet, try as I might I couldn&#8217;t find something that did these things better than xmms despite the fact thaat xmms would crash at least once a day.</p>
<p>But now I have found <a href="http://www.musicpd.org/">Music Player Daemon (MPD)</a>, or rather I&#8217;ve found that it does ESD output even though the documentation makes no mention of it.  If the bloody manpage had just told me it was supported instead of implying that only OSS and ALSA were possible I would have switched months ago when I first looked at it, bah.  Anyway, I have keyboard and lirc control by setting up shortcuts for running mpc with various args, a gui in gmpc (ugly though it is) and even an <a href="http://mpd.wikicities.com/wiki/Client:Mpd-applet">applet</a> to sit on my menu bar.  Oh and a <a href="http://www.frob.nl/scribble.html">plugin</a> for <a href="http://www.last.fm/user/Ghworg/">last.fm</a>, well it&#8217;s really a client not a plugin but it doesn&#8217;t sound right calling it that.</p>
<p>There is one minor irritation with MPD, it makes a database of your songs and uses that to reference the files rather than filesystem paths.  Now I have all my music under one dir so it&#8217;s not a huge hassle, but it was a bit irritating until I saw a little python script on the wiki to play files from anywhere on the system.  Wasn&#8217;t quite what I wanted but it showed me the way and tada:</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span></p>
<p><span class="kw1">import</span> <span class="kw3">os</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p>mpdRoot = <span class="st0">&#8216;/mnt/data/Music&#8217;</span></p>
<p><span class="kw1">if</span> <span class="kw1">not</span> <span class="kw2">len</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span> &gt; <span class="nu0">1</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> &gt;&gt;sys.<span class="me1">stderr</span>, <span class="st0">&#8216;Usage:<span class="es0">\n</span>%s &lt;files&gt;&#8217;</span> % <span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> still_updating<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="st0">&#8216;Updating DB&#8217;</span> <span class="kw1">in</span> <span class="kw3">os</span>.<span class="me1">popen</span><span class="br0">&#40;</span><span class="st0">&#8216;mpc&#8217;</span><span class="br0">&#41;</span>.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>
links = <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
<span class="kw1">for</span> <span class="kw2">file</span> <span class="kw1">in</span> <span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#91;</span><span class="nu0">1</span>:<span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">isabs</span><span class="br0">&#40;</span><span class="kw2">file</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; full = <span class="kw2">file</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; full = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="kw3">os</span>.<span class="me1">getcwd</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, <span class="kw2">file</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; filepath = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">realpath</span><span class="br0">&#40;</span>full<span class="br0">&#41;</span><br />
&nbsp; &nbsp; pre = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">commonprefix</span><span class="br0">&#40;</span> <span class="br0">&#91;</span>filepath, mpdRoot<span class="br0">&#93;</span> <span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; <span class="co1">#print pre</span><br />
&nbsp; &nbsp; head = <span class="st0">&#8221;</span><br />
&nbsp; &nbsp; remain = filepath<span class="br0">&#91;</span><span class="kw2">len</span><span class="br0">&#40;</span>pre<span class="br0">&#41;</span><span class="nu0">+1</span>:<span class="br0">&#93;</span><br />
&nbsp; &nbsp; links.<span class="me1">append</span><span class="br0">&#40;</span>remain<span class="br0">&#41;</span></p>
<p><span class="co1">#print links</span><br />
<span class="kw3">os</span>.<span class="me1">system</span><span class="br0">&#40;</span><span class="st0">&#8216;mpc clear&#8217;</span><span class="br0">&#41;</span><br />
<span class="kw3">os</span>.<span class="me1">system</span><span class="br0">&#40;</span><span class="st0">&#8216;mpc update&#8217;</span><span class="br0">&#41;</span><br />
<span class="kw1">while</span> still_updating<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">pass</span></p>
<p><span class="kw1">for</span> link <span class="kw1">in</span> links:<br />
&nbsp; &nbsp; <span class="co1">#print &#8216;os.system(mpc add &quot;%s&quot;)&#8217; % link</span><br />
&nbsp; &nbsp; <span class="kw3">os</span>.<span class="me1">system</span><span class="br0">&#40;</span><span class="st0">&#8216;mpc add &quot;%s&quot;&#8217;</span> % link<span class="br0">&#41;</span><br />
<span class="kw3">os</span>.<span class="me1">system</span><span class="br0">&#40;</span><span class="st0">&#8216;mpc play&#8217;</span><span class="br0">&#41;</span><br />
&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2005/10/music-player-daemon/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Browsing network shares</title>
		<link>http://blog.trollgod.org.uk/2005/10/browsing-network-shares/</link>
		<comments>http://blog.trollgod.org.uk/2005/10/browsing-network-shares/#comments</comments>
		<pubDate>Sun, 02 Oct 2005 21:22:39 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Admin]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=19</guid>
		<description><![CDATA[<p>I wanted a way to browse network shares without having to mount them first or resorting to clunky guis like nautilus. So I worked out how to do it using autofs. The engine behind this being the two scripts for NFS and Samba. Combined with a standard autofs setup that references them I can <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2005/10/browsing-network-shares/">Browsing network shares</a></span>]]></description>
			<content:encoded><![CDATA[<p>I wanted a way to browse network shares without having to mount them first or resorting to clunky guis like nautilus.  So I worked out how to do it using autofs.  The engine behind this being the two scripts for <a href="http://blog.trollgod.org.uk/linux/autonetnfs/">NFS</a> and <a href="http://blog.trollgod.org.uk/linux/autonetsmb/">Samba</a>.  Combined with a standard autofs setup that references them I can just browse shares by visiting &quot;/smb/$MACHINENAME/&quot; and then tab-completion works from there.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2005/10/browsing-network-shares/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
