The Junction's Journal
 
[Most Recent Entries] [Calendar View] [Friends]

Below are the 5 most recent journal entries recorded in The Junction's InsaneJournal:

    Monday, December 7th, 2009
    2:07 pm
    next whenever

    It appears from a couple of confusing arrangements recently that Americans1 who say e.g. ‘next Friday’ mean ‘Friday next week’. Whereas I, being literal-minded, interpret it as ‘counting from today (which is Monday), the next Friday is Friday this week’.

    In other time-related language, people here say ‘quarter of’, and I still can’t remember if that means ‘quarter past’ or ‘quarter to’. And if I say ‘half ten’ they don’t know if I mean 9:30 or 10:30 (it’s the latter).

    1 or some people around here, anyway.

    Friday, June 19th, 2009
    10:39 am
    dns323 podcast and torrent downloader

    I’ve expanded on my previous podcast downloader program so that it gets torrents as well. I was running Automatic but it seemed silly to have two programs doing more or less the same thing.

    I also didn’t like the configuration of Automatic, which has a global set of regexps it applies to all feeds to decide whether to download an item. My program has separate regexps for each feed1 which I think is a bit easier to deal with. In order to make the config file easy to parse, it is actually another Ruby file, which is read with instance_eval. By having methods defined as feed and matches the config file can just use those and look relatively sane:

    feed 'http://some.feed.url/blah.rss'
    matches 'title.to.match.*\d+'

    (Some people would call this a DSL, but I think that’s stretching a point)

    To make the torrents get into Transmission, the torrent downloader we’re using, I just call the transmission-remote command. Sometimes it’s easier to use what works.

    So here’s the full program (see my previous post for how to set things up on the DNS-323):

    #!/ffp/bin/env ruby
     
    require 'open-uri'
    require 'rss'
     
    CONFFILE='/ffp/etc/mypodder2.conf'
    PODCASTDIR='/mnt/HD_a2/podcasts'
    TORRENTDIR='/mnt/HD_a2/torrents'
    TORRENT_UPLOAD='/ffp/bin/transmission-remote "127.0.0.1:9091" -a "%s"'
     
    class ConfigParser
    	def initialize(feeds)
    		@feeds = feeds
    	end
     
    	def parse(file)
    		instance_eval(File.read(file), file)
    	end
     
    	def feed(url)
    		@current = Feed.new(url)
    		@feeds << @current
    	end
     
    	def matches(pattern)
    		@current.add_pattern(pattern) if @current
    	end
     
    	alias :or :matches
     
    end
     
    class Feed
    	def initialize(url)
    		@url = url
    		@patterns = []
    	end
     
    	def uri
    		@url
    	end
     
    	def add_pattern(pattern)
    		if(pattern && pattern.length > 0)
    			@patterns << Regexp.new(pattern, true)
    		end
    	end
     
    	def allow?(item)
    		icompare = item.title
    		@patterns.empty? || @patterns.find {|p| p =~ icompare}
    	end
    end
     
    class Main
    	def initialize(options = {})
    		@options = {:config => CONFFILE, :verbose => false}.merge(options)
    		@feeds = []
    		read_config
    	end
     
    	def read_config
    		ConfigParser.new(@feeds).parse(@options[:config])
    	end
     
    	def vprintln(sometext)
    		if(@options[:verbose])
    			puts sometext
    		end
    	end
     
    	def torrent?(item)
    		item.enclosure.type =~ /.*torrent/
    	end
     
    	def run()
    @feeds.each do |feed|
        vprintln "checking feed #{feed.uri}"
        rss_content = ""
        open(feed.uri) do |f|
            rss_content = f.read
        end
        rss = RSS::Parser.parse(rss_content, false)
     
        rss.items.each do |item|
            vprintln " + checking item #{item.title}"
            if(item.enclosure && feed.allow?(item))
                iurl = item.enclosure.url
                vprintln " + + allowed item #{iurl}"
                ctitle = rss.channel.title.gsub(/\W/, '_')
    		base = PODCASTDIR
    		base = TORRENTDIR if torrent?(item)
                system("mkdir -p #{File.join(base, ctitle)}")
                system("chmod a+rw #{File.join(base, ctitle)}")
                ifile = File.join(base, ctitle, File.basename(iurl))
                unless File.exists?(ifile)
                	puts "About to download #{iurl} as #{ifile}"
                	system("wget -O #{ifile} #{iurl}")
     
    		if(torrent?(item) && File.exists?(ifile))
    			system(sprintf(TORRENT_UPLOAD, ifile))
    		end
                else
                	vprintln " + + file exists"
                end
            end
        end                                
    end
    	end
    end
     
    if __FILE__ == $0
    	require 'optparse'
     
    	options = {}
     
    	opts = OptionParser.new do |op|
    		op.on("-f CONFIG", "--config CONFIG", "Specify config file (default #{CONFFILE})") do |f|
    		      options[:config] = f
    	        end
     
    		op.on("-v", "--verbose", "Output messages") do
    		      options[:verbose] = true
    	        end
     
    	        # No argument, shows at tail.  This will print an options summary.
    	        op.on_tail("-h", "--help", "Show this message") do
    	              puts opts
    	              exit
    	        end
     
    	end
     
    	opts.parse(ARGV)
    	Main.new(options).run
    end

    1 At the moment, it ‘OR’s together multiple regexps on a single feed, but I’m thinking I may change that so it’s easier to exclude certain matches as well as include.

    Thursday, June 25th, 2009
    1:12 pm
    Comcast are scum

    The ‘Digital Television Switchover’ took place here a couple of weeks ago. Not long after, we received this letter from Comcast[PDF 900kB]. While I suspect it doesn’t say anything that is actively illegal, I do think it could be highly misleading and is taking advantage of less well informed people1.


    Q: How do I get my signal back?
    A: There are several options, but the easy answer is to call Comcast.

    How do you quantify ‘easy’? Comcast’s offer probably is ‘easy’ in the sense that once you request their service, they’ll send an installer over to set everything up for you. Of course RCN, Verizon, DirecTV, Dish Network or others would do the same thing, so it pays to shop around, if that’s what you want. They’ll all need to you stay at home to wait for the installer, then add some extra boxes to the outside of your house, drill holes and run cable around.

    Assuming you have a TV antenna in place, I think it’s quite easy to buy a digital converter box, connect the antenna to it, and connect it to the TV.


    Q: How do I get FREE Basic Cable?
    A: It’s easy… sign up for Internet and/or phone (each starting at just $24.95/mo.)

    So this is that special kind of ‘free’ where actually you have to pay for something. Whichever deal you choose you’re out a minimum of $10 every month to Comcast, and reading the small print you may also have to pay for equipment, installation, taxes and other fees. Don’t forget, it’s only ‘free’ for the first year. Do you expect to watch TV for longer than a year?

    Compare this to a digital converter box. You can request a converter box coupon which gives you $40 off the price. The boxes are selling for around $40 – $60, so your maximum outlay will be about $20 (plus sales tax), with no ongoing cost. If you were previously watching broadcast TV, you can use the same antenna.

    Should you take up Comcast’s offer?
    I don’t intend to. I don’t think it gains you anything other than another monthly bill. If you just want to get broadcast TV back, a converter box is a cheaper option. If you really want cable, look around at all the possibilities.

    1 Though my impression of US culture is that there is more of an expectation for people to inform themselves to avoid being taken advantage of.

    Thursday, August 13th, 2009
    1:20 pm
    Health Care Debate part 1

    I’ve been meaning to write comparing British and US health care for a while, but it’s not a very easy topic to get around. However it is the main subject in the news these days so it’s about time I weigh in.

    The most emotive piece I’ve heard on the radio this week was from one of many ‘town hall’ meetings (I forget which). A sobbing woman says, “The president is trying to make us like Russia. I don’t want America to be Socialist!”

    Of course, being me, this leaves me thinking, “but why?”. The speaker obviously thinks ‘Socialist’ is a ‘bad word’ – I don’t. (I’ll leave aside the debate over whether Russia is really socialist any more). Since the quote doesn’t give any more reasoning, I’m left to wonder what this woman is actually opposed to – she clearly feels strongly about it.

    Unfortunately, to me, the opposite of socialism seems to be selfishness. Selfishness in health care seems to lead to a situation where you are fine while you remain healthy but if you are unlucky enough to get sick you’d better hope you can afford it. A lot of illness isn’t selfish, by the way – the flu is happy to spread fairly to all people, given the chance.

    In practice paying for US health care is somewhere along the selfish/social scale. As companies or organisations buy group insurance plans, they form small pockets of socialness. The only reason insurance works is because it spreads the cost across a group of people, with the assumption that not everyone will suffer illness. So people who pay insurance premiums and are healthy, are necessarily subsidising the health care of people in the same group who are less healthy. That sounds like socialism to me.

    Of course, the American argument is that people have freedom of choice about what insurance they buy, or don’t buy1, and that the current debate is about the government taking away that freedom. I need to think more about that, so maybe more later.

    1 I live in Massachusetts, and it is mandatory for people here to have some kind of health insurance.

    Tuesday, November 24th, 2009
    1:57 pm
    bash twitter

    There are probably lots of variants out there. In fact mine is largely copied from here Inspired by BLT

    #!/bin/bash
    # a twitter client (uses .netrc for auth)
     
    confdir=~/.bt
    seenfile=$confdir/seen
    feedstyle=$confdir/btfeed.xsl
     
    if [ "$1" == "-h" ]; then
     echo " use: $(basename $0) -h | [ tweet ]"
     echo "      -h help"
     echo "      -i install"
     echo "      no arguments gets latest updates"
     exit
    fi
     
    function binstall {
     local sheet='<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
     
    <xsl:template match="/">
    <xsl:apply-templates select="//status"/>
    </xsl:template>
     
    <xsl:template match="status">
    <xsl:value-of select="id"/><xsl:text>: &lt;</xsl:text><xsl:value-of select="user/screen_name"/><xsl:text>&gt; </xsl:text>
        <xsl:value-of select="text"/><xsl:text>\n
     
    </xsl:text>
    </xsl:template>
    </xsl:stylesheet>
    '
     if [ ! -d $confdir ]; then mkdir -p $confdir; fi
     if [ ! -e $seenfile ]; then touch $seenfile; fi
     if [ ! -e $feedstyle ]; then
       echo -e $sheet > $feedstyle
     fi
    }
     
    function friends { 
     local tnow=$( date --utc +%s )
     local tthen=$( date --utc --reference=$seenfile +%s )
     if [ $(( tnow - tthen < 60 )) = 1 ]; then
       return
     fi
     local tmpfile=$( mktemp $confdir/result.XXXXXXXX )
     curl --connect-timeout 5 -s -n $1 | xsltproc $feedstyle - > $tmpfile
     local tmpu=$( mktemp ~/.bt/uniques.XXXXXXXX )
     cat $seenfile $tmpfile | sort -n | uniq -u > $tmpu
     cat $seenfile $tmpfile | sort -n | uniq > $seenfile
     cat $tmpu $tmpfile | sort -n | uniq -d | cut -d':' -f2-
     echo
     rm $tmpfile $tmpu 
     touch $seenfile
    }
     
    function update {
     curl -s -n -d "status=$msg" $1 &>/dev/null || echo "tweet broke"
    }
     
     
    if [ "$1" == "-i" ]; then
     binstall
     exit
    fi
     
    if [ -t 0 ]; then msg="$*"; else msg="$(cat -)"; fi
     
    if [ "$msg" ];then
     update http://twitter.com/statuses/update.xml
    else
     friends http://twitter.com/statuses/friends_timeline.xml
    fi

    Prerequisites

    • bash
    • curl
    • xsltproc
    • mktemp

    How to
    1. Copy the above script into ~/bin/bt and make it executable.
    2. Write a ~/.netrc containing something like this:

    machine twitter.com
    login exampleuser
    password examplepassword
    

    3. run bt -i to ‘install’. This will create a ~/.bt/ directory with a stylesheet and seen status file.
    4. To check your friends timeline run bt with no arguments.
    5. To post a message run bt <message> or pipe into bt. (Maybe for the next enhancement I’ll check the length of the message).
    6. For friends updates while you use your bash command line, put something like this in your ~/.bashrc:
    export PROMPT_COMMAND="bt; $PROMPT_COMMAND"
    

The Junction   About InsaneJournal