toshia/mikutter-sub-parts-client · GitHub
多分みんな入れてるプラグインじゃないでしょうか。
viaを表示するプラグインです。
ただ、このプラグイン、クライアント名をクリックしても何も起きないのですよね。
ブラウザでクライアントのページを開いてほしいなー、とか思うじゃないですか。
実装しました。
pocke/mikutter-sub-parts-client · GitHub
URLが捨てられてる
捨てられてるんですよ、URL。
試しにmikutterコンソールを開いて
Plugin.create :hoge do on_appear do |msgs| msgs.each do |msg| p msg end end end
とかしてみると、下記の形式でterminalに受信したツイートが出力されます(見やすいように適宜改行を入れています)。
{ :created_at=>"Sat Jan 18 09:38:04 +0000 2014", :id=>424475770371592192, :id_str=>"424475770371592192", :message=>"にゃーん", :source=>"mikutter", :truncated=>false, :replyto=>nil, :in_reply_to_status_id_str=>nil, :receiver=>nil, :in_reply_to_user_id_str=>nil, :in_reply_to_screen_name=>nil, :user=>User(@p_ck_), :geo=>nil, :coordinates=>nil, :place=>nil, :contributors=>nil, :retweet_count=>0, :favorite_count=>0, :entities=>{ :hashtags=>[], :symbols=>[], :urls=>[], :user_mentions=>[] }, :favorited=>false, :retweeted=>false, :lang=>"ja", :created=>2014-01-18 18:38:04 +0900, :exact=>false, :modified=>2014-01-18 18:38:04 +0900 }
すると、sourceとして"mikutter"がありますが、mikutterが指し示す筈のURLはどこにも見当たりません。
ですが、下記のコードをmikutterコンソールから叩くと、twitterからAPIを叩いた時点ではURLの情報が存在していることがわかります。
(Service.primary.twitter/'statuses/show/424475770371592192').json({}).next do |x| p x end
{ :source=>"<a href="http://mikutter.hachune.net/" rel="nofollow">mikutter</a>", ...}
出力されるHashの中に:sourceというキーがあり、ここにクライアントの情報が入っています。
つまり、mikutterのどこかで:sourceの内容からクライアント名だけが抽出されていると言うことになります。
で、抽出されているのがここです。
##### file: core/lib/mikutwitter/api_call_support.rb def message(msg) cnv = msg.convert_key(:text => :message, :in_reply_to_user_id => :receiver, :in_reply_to_status_id => :replyto) cnv[:source] = $1 if cnv[:source].is_a?(String) and cnv[:source].match(/^<a\s+.*>(.*?)<\/a>$/) cnv[:created] = (Time.parse(msg[:created_at]) rescue Time.now) cnv[:user] = Message::MessageUser.new(user(msg[:user]), msg[:user]) cnv[:retweet] = message(msg[:retweeted_status]) if msg[:retweeted_status] cnv[:exact] = [:created_at, :source, :user, :retweeted_status].all?{|k|msg.has_key?(k)} message = cnv[:exact] ? Message.rewind(cnv) : Message.new_ifnecessary(cnv) message end
このcnv[:source] = ...行でクライアント名部分だけを抜き出しているようです。
ということで、url部分も取得するようにパッチをあてました。
mikutter の Message に source の URL を含めるパッチ
これで cnv[:source_url] にクライアントのURLが格納されます。
先ほどの用に流れてきたMessageを眺めてみると、
{ :created_at=>"Sat Jan 18 09:38:04 +0000 2014", :id=>424475770371592192, :id_str=>"424475770371592192", :message=>"にゃーん", :source=>"mikutter", :truncated=>false, :replyto=>nil, :in_reply_to_status_id_str=>nil, :receiver=>nil, :in_reply_to_user_id_str=>nil, :in_reply_to_screen_name=>nil, :user=>User(@p_ck_), :geo=>nil, :coordinates=>nil, :place=>nil, :contributors=>nil, :retweet_count=>0, :favorite_count=>0, :entities=>{ :hashtags=>[], :symbols=>[], :urls=>[], :user_mentions=>[] }, :favorited=>false, :retweeted=>false, :lang=>"ja", :source_url=>"http://mikutter.hachune.net/", :created=>2014-01-18 18:38:04 +0900, :exact=>false, :modified=>2014-01-18 18:38:04 +0900 }
となっており、:source_urlが確認できますね。
これでプラグインを作成する下準備が整いました。
プラグインを書き換える
最初sub-parts-clientのソースを見た時、なんだこれはわけがわからんーーーって感じでした。
とりあえず、Gdk::SubPartsの宣言でも探してみます。そして、Gdk::SubPartsを使っているコードも探してみます。
……
core/mui/cairo_sub_parts_helper.rb で宣言されていますね。
また、core/mui/の中にそれっぽいファイルがいくつかあるので、まとめて開いてみましょう。
$ vim core/mui/cairo_sub_parts* -p
すると、cairo_sub_parts_favorite, cairo_sub_parts_retweetで宣言されているGdk::SubPartsFavorite, Gdk::SubPartsRetweetは両方ともGdk::SubPartsVoterを継承しています。
Gdk::SubPartsVoterはその名の通りcairo_sub_parts_voter.rbで宣言されているので、それを見れば良さそうです。
initializeあたりが参考になりそうですね。
##### file: core/mui/cairo_sub_parts_voter.rb .... def initialize(*args) super @icon_width, @icon_height, @margin, @votes, @user_icon = 24, 24, 2, get_default_votes.to_a, Hash.new @avatar_rect = [] @icon_ofst = 0 helper.ssc(:click){ |this, e, x, y| ofsty = helper.mainpart_height helper.subparts.each{ |part| break if part == self ofsty += part.height } if ofsty <= y and (ofsty + height) >= y case e.button when 1 if(x >= @icon_ofst) index = @avatar_rect.bsearch_first {|range| range.include?(x) ? 0 : range.first <=> x} user = get_user_by_point(x) if user Plugin.call(:show_profile, Service.primary, user) end end end end false } .... end ....
参考になりそうなとこだけ抜き出してみました。
helper.ssc(:click){ ...... なあたりが怪しそうですね。
helper.subparts.eachのブロックで、ofstyにheightを追加していっているようです。
そして、後ろのif文でクリックした座標が表示されているアイコンの中に収まってるか確認している感じでしょうね。
case文は、マウスのボタンでしょう(1なら左クリックと見た!)
って感じで、add_linkメソッドを追加してrenderで呼び出してます。
Plugin.create :sub_parts_client do # ツイートが投稿されるのに使われたクライアントアプリケーションの名前をTL上に表示する class Gdk::SubPartsClient < Gdk::SubParts .... def add_link(x_size) return if @hasLink @hasLink = true helper.ssc(:click) do |this, e, x, y| ofsty = helper.mainpart_height helper.subparts.each do |part| break if part == self ofsty += part.height end if ( ofsty <= y and y <= (ofsty + height) ) and ( (width - x_size - @margin * 2) <= x ) then Gtk::openurl(message[:source_url]) if e.button == 1 end end end end end
@hasLinkとか気持ち悪くなってるのは、複数回add_linkが実行されるとよろしくない感じだからです。
initializeからadd_linkを呼び出せればいいんでしょうけど、それが難しそうだったので…
そんな感じに参考に書いた感じです。
後半ブログ書くのめんどくさくなっててきとーである。うん。
mikutter本体にパッチをあてないとどうにしろ無理っぽい感じなのでぐぬぬって感じです。
モンキーパッチな感じでやるのも考えたのですが、うまくいかないしいいやって思って諦めました。