w3mでもFastladderが読みたい!

w3mでもFastladderが読みたい。でも、touch用のインタフェースを使おうにも、w3mFastladderを相当嫌って

This cookie was rejected to prevent security violation.

と言われて、ログインすらできない。参考
w3mにパッチをあててこれを回避したりするのはなんか悔しいから、local cgiFastladder用のインタフェースを実現してみた。ちょっと手直しをすればLivedoor readerでも使えるかもしれない。

ただ、RubyのWWW::Mechanizeでcookieを保存する方法がよくわからなくて、毎回ログインしているので、動作がちょっともたつく。keyとvalueから適当なクッキーを生成して、Mechanizeに食わせることができるといいんだけど・・・。

あとw3mのlocal cgi機能を使って、w3m本体の制御をしているから、普通のCGIとしては公開できない。

fastladder.rb

Fastladder APIのインタフェース。ほかのやつにも使えるかもしれない。

#! /opt/local/bin/ruby -w
# -*- mode:ruby; coding:utf-8 -*-
#
# fastladder.rb -
#
# Copyright(C) 2008 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2008/07/13 09:54:58
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#
require 'rubygems'
require 'www/mechanize'
require 'json'

class Fastladder
  Base='http://fastladder.com/'
  attr_reader :api_key
  def initialize(api_key=nil)
    @agent = WWW::Mechanize.new
    @api_key  = api_key
  end

  # login to get api key
  def login(username,password)
    login = @agent.get(Base).forms.first
    login.username = username
    login.password = password
    @agent.submit(login)

    @api_key = @agent.cookies.find{|c| c.name=='reader_sid'}.value
  end

  def subs(unread=0)
    JSON.parse @agent.post(Base+'/api/subs',{'ApiKey'=>@api_key,'unread'=>unread}).body
  end

  def unread(sid)
    JSON.parse @agent.post(Base+'/api/unread',{'ApiKey'=>@api_key,'subscribe_id'=>sid}).body
  end

  def touch_all(sid)
    JSON.parse @agent.post(Base+'/api/touch_all',{'ApiKey'=>@api_key,'subscribe_id'=>sid}).body
  end

  def pin()
    JSON.parse @agent.post(Base+'/api/pin/all',{'ApiKey'=>@api_key}).body
  end

  def pin_add(title,url)
    JSON.parse @agent.post(Base+'/api/pin/add',{'ApiKey'=>@api_key,'link'=>url,'title'=>title}).body
  end

  def pin_clear
    JSON.parse @agent.post(Base+'/api/pin/clear',{'ApiKey'=>@api_key}).body
  end
end

pin.cgi

ピン立て用。ピンの一覧と、クリアができる。

#! /usr/bin/env ruby
# -*- mode:ruby; coding:utf-8 -*-
#
# feeds.rb -
#
# Copyright(C) 2008 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2008/07/13 09:24:36
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#
#! /opt/local/bin/ruby -w
# -*- mode:ruby; coding:utf-8 -*-
#
# fastladder.rb -
#
# Copyright(C) 2008 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2008/07/13 09:54:58
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#

require 'fastladder'
require 'cgi'

cgi = CGI.new 'html4'

fl = Fastladder.new
fl.login('<username>','<password>')


if cgi['mode'] == 'clear'
  fl.pin_clear
  print <<-EOF
Content-Type: text/html
Content-Length: 0
W3m-control: BACK
W3m-control: RELOAD

  EOF
else
  cgi.out do
    cgi.html do
      cgi.head do
        cgi.title{ "ピン一覧 - Fast3m" } 
      end +
        cgi.body do
        cgi.h1{'ピン一覧 - Fast3m'} +
          cgi.ul do
          fl.pin.map {|item|
            cgi.li{ cgi.a('href'=>item['link']){ 
                item['title']} } }.join +
            cgi.form{
            cgi.input('type'=>'hidden','name'=>'mode','value'=>'clear') +
            cgi.input('type'=>'submit','value'=>'clear')
          }
        end
      end
    end
  end
end

feeds.cgi

フィードを読むやつ。既読化とピン立てができる。

#! /usr/bin/env ruby
# -*- mode:ruby; coding:utf-8 -*-
#
# feeds.rb -
#
# Copyright(C) 2008 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2008/07/13 09:24:36
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#

require 'fastladder'
require 'cgi'

cgi = CGI.new('html4')
fl = Fastladder.new
fl.login('<username>','<password>')

if cgi['mode'] == 'touch' then
  x = ''
  cgi.params.each do|name,value|
    if name =~ /\Apin_(.*)\Z/ then
      fl.pin_add(cgi["title_#{$1}"],cgi["link_#{$1}"])
    end
  end
  fl.touch_all(cgi['sid'])
  print <<-EOF
Content-Type: text/html
Content-Length: 0
W3m-control: GOTO file:///cgi-bin/feeds.cgi

  EOF
elsif cgi['sid'] != '' then
  feeds = fl.unread(cgi['sid'])
  ch    = feeds['channel']
  cgi.out{
    cgi.head{
      cgi.title { "#{feeds['channel']['title']} - Fast3m" } }+
    cgi.body{
      cgi.h1{
        cgi.a('href'=>ch['link']){
          "#{ch['title']} - Fast3m" 
        } } +
      cgi.h2{ ch['description'] }  +
      cgi.form{
        i  = 0
        feeds['items'].map{|item|
          i += 1
          cgi.h2{ 
            cgi.input('type'=>'checkbox','name'=>"pin_#{i}"){} +
            cgi.input('type'=>'hidden','name'=>"link_#{i}",'value'=>item['link']){} +
            cgi.input('type'=>'hidden','name'=>"title_#{i}",'value'=>item['title']){} +
            cgi.a('href'=>item['link']){item['title']} } +
          cgi.div{ item['body'] }
        }.join +
        cgi.p{}+
        cgi.input('type'=>'hidden','name'=>'sid','value'=>cgi['sid']) +
        cgi.input('type'=>'hidden','name'=>'mode','value'=>'touch') +
        cgi.input('type'=>'submit','value'=>'既読化')
      }
    } 
  }
else
  subs = fl.subs(1)
  cgi.out {
    cgi.html{
      cgi.head{ cgi.title{ "未読一覧 - Fast3m" } } +
      cgi.body{ 
        cgi.h1{ "未読一覧 - Fast3m" } +
        cgi.p { cgi.a('href'=>"pin.cgi?api_key=#{fl.api_key}"){ "ピン一覧" } } +
        cgi.ul{
          subs.map{|x| cgi.li{ cgi.a('href'=>"feeds.cgi?sid=#{x['subscribe_id']}"){ 
                "#{x['title']} (#{x['unread_count']})"  }}}.join
        }
      }
    }
  }
end