w3mでもFastladderが読みたい!
w3mでもFastladderが読みたい。でも、touch用のインタフェースを使おうにも、w3mはFastladderを相当嫌って
This cookie was rejected to prevent security violation.
と言われて、ログインすらできない。参考。
w3mにパッチをあててこれを回避したりするのはなんか悔しいから、local cgiでFastladder用のインタフェースを実現してみた。ちょっと手直しをすれば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