0

Gyazz.comの更新をSkypeに通知

作った https://github.com/shokai/gyazzchecker-skype

MongoDB + MacOSX + Skype + Ruby1.8.7で動く。
Skype APIを使うためMac固定なのと、rb-skypemacというgemがRuby1.9系で動かないので1.8.7で。
cronではSkype APIが動かないのでMacのLaunchAgentにインストールするスクリプトを付けておいた。


http://gyazz.comという増井先生がwikiがあり、アウトラインエディタ機能とシンプルな賢い記法で大変便利。

RSSもあるのだが(http://gyazz.com/wiki名/rss.xml にある)
みんなにもっとwikiを見て欲しいのでSkypeチャットに更新通知を投げるツールを作った。
5分ごとに更新があったページのdiffを投げてる。



https://github.com/shokai/gyazzchecker-skype

MongoDB + MacOSX + Skype + Ruby1.8.7で動く。
Skype APIを使うためMac固定なのと、rb-skypemacというgemがRuby1.9系で動かないので1.8.7で。
cronではSkype APIが動かないのでMacのLaunchAgentにインストールするスクリプトを付けておいた。

0

twitterの発言をskypeに投げる

研究会のskype chatで存在感がない人を忘れないために、研究会のtwitterアカウントでfollowしている人の最近の発言をランダムに投稿するようにしている

3時間ごとに投げる。


ここにコードおいてある
https://github.com/shokai/skype-chat-gateway-mac/tree/master/tools/twitter


skypeへの投稿はSkype Chat Gatewayと、WebブラウザからSkypeチャットできるやつ作ったに書いたskype-chat-gatewayを使っている。HTTPでskype chatが使えるスゴイ奴だよ

0

Skype Chat Gatewayと、WebブラウザからSkypeチャットできるやつ作った

半年ぐらい前に作って、書くのを完全に忘れてた。
Skype Botの類が簡単に作れるようになるし、スマホの重いSkypeクライアント起動しなくてもチャット読めたりしてなかなか便利です。skype-socket-gatewayは捨てましょう。

 

Mac版とLinux版がある。Mac版はchatの読み書きができるけど、Linux版はAPIがよくわからなくて書き込みしかできない。

動かし方はそれぞれREADMEに書いたので読んで欲しい
起動するとHTTPサーバーがport 8787で立ち上がる。
自分のプログラム <--(HTTP)--> Skype-Gateway <--(AppleScript)--> Skype.app
という感じで通信する。

HTTP-POSTでchatに発言できるので、bot等が作りやすい。
例えばcurlで発言する
curl -d 'hello!!' http://localhost:8787
これでchatにhello!!と投稿される。


Mac版にはLaunchAgentに登録する.plistファイルも付けておいたので、Mac起動と同時にskype-chat-gatewayも自動起動させれる。

 

ついでにMac版には “WebUI” というディレクトリが同梱されている。
Webブラウザ上でチャットが使える。

SinatraアプリがMac版skype-chat-gatewayと通信している。
スマホ版Skypeが重すぎて常時起動してられないのでちゃちゃっと作ってみた。
ChromeやSafariで開いておくとWebkit NotificationでGrowlのような通知が出るので、本格的にSkype起動して無くても良くなってくる。

Linux版はチャットが読めないのでWebUI付けてない。

0

skype-socket-gatewayを作った

Skypeのグループチャットにbotを放ったり色々したかったので作った。

Skype APIはSkypeが起動しているマシンの中でSkypeのプログラムと自分のアプリを通信させて使う物で、developer.skype.comにAPIのドキュメントがある。電話をかけたりチャットの中身を取得したり発言したりできる。

Skypeが起動しているマシンでskype socket gatewayを起動しておくと、他のマシンからもtelnetでSkype APIが使える。また、全チャット(含むグループチャット)のデータがJSONでどんどん流れてくるようになっている。

うちではWindows XPのネットブックでbotアカウントでSkypeを起動してあった。Skype chatはP2Pなのでログをそれぞれが持っていて、後で接続してきた人は先に居た人から取得する様になっている。だから、ただ何もしなくてもずっとオンラインの人がいるだけでログの流れが良くなる。
で、そのbotアカウントを真なるbotにするために、Windows用のActiveScriptRuby 1.8.7でskype socket gatewayを動かしてそこに別のLinuxのサーバーから複数のbotが接続して色々処理をしている。

Linux上で動くSkype用のbotを作る方法 – muddy brown thangにXvfbを使ってlinuxで仮想フレームバッファを作ってSkype APIを使う方法が解説されてるけど、なんかLinuxが難しくて挫折したのでwindowsでも動くsocket gatewayを作った。


■ソースコード
githubに全部置いておいた
shokai's skype-socket-gateway at master – GitHub


■インストール

git clone git://github.com/shokai/skype-socket-gateway.git

必要なgemもインストールする
gem install Ruby4Skype json eventmachine

Ruby4Skypeというのを使っているので、Windows、Mac、Linuxで動く。ただしRuby4Skypeが64bit MacOSXでは動かない。Linuxも、Ruby4Skypeのlib/skype/os/linux.rbを修正してinitialize methodのsuperにapp_nameを渡すように修正しないと動かない。

それとWindowsでRuby4Skypeを動かすには色々DLLを入れないとダメ → WinXPでgem install Ruby4Skypeするメモ – yuisekiのいまさらruby厨日記 – Rubyist


■起動する
先にSkypeを起動しておく。

ruby skype-gateway.rb
でport 20000で起動する。


■使う
telnetで接続する。
telnet 192.168.1.37 20000

そしてそのまま
CALL shokaishokai
MESSAGE shokaishokai hello work!!
とか書く。Skype APIがそのまま実行できる。
レスポンスはJSONで来る。

あと、接続しているだけで全てのchatの発言が流れてくる。


■Windowsのスタートアップに登録する
run_skype_gateway.bat というバッチファイルを作る
"C:\Program Files\ruby-1.8\bin\ruby.exe" "C:\Document and Settings/sho/src/ruby/skype-socket-gateway/skype-gateway.rb"
中身はこの1行でいい。これをスタートメニューのスタートアップに入れておけば自動起動できる。


■Skype botを作る
RubyだとTCPSocketクラスを使うと簡単に作れる。

キーワードに反応する単純なbotの例。誰かが「ざんまい」と書くと、即座に「ざんまい行きたい!」と返す。
samples/zanmai_bot.rb at master from shokai's skype-socket-gateway – GitHub
require 'rubygems'
require 'socket'
require 'json'
require 'eventmachine'
$KCODE = 'u'

HOST = "192.168.1.37"
PORT = 20000

begin
s = TCPSocket.open(HOST, PORT)
s.puts "MESSAGE shokaishokai ざんまいbot start"
rescue => e
STDERR.puts e
exit 1
end

EventMachine::run do

EventMachine::defer do
loop do
res = s.gets
exit unless res
res = JSON.parse(res) rescue next
p res
if res['type'] == 'chat_message'
if res['body'] =~ /ざんまい/ # キーワードに反応
s.puts "CHATMESSAGE #{res['chat']} ざんまい行きたい!"
elsif res['body'] =~ /かず(すけ|助)/
s.puts "CHATMESSAGE #{res['chat']} かずにゃんぺろぺろ"
end
end
end
end

EventMachine::defer do
loop do
mes = gets
s.puts mes if mes
end
end

end


これにもう少し語彙を追加すると、だいたい俺の人格と機能を8割方再現したbotが作れる。
shokai_bot.rb at master from shokai's skype-bots – GitHub
6a8dae3e0028f2f870f194cdbec2af75.png


あと、全chatをmongo dbに入れて検索したりできるbotなんかもいる。超便利。
tools/skype_chat_store_mongod.rb at master from shokai's skype-socket-gateway – GitHub
fecba229c251c20a4543e21bd1395929.png


はてなランドに自分のskypeの発言を送るなんて事もできる
hatenaland_proxy.rb at master from shokai's skype-bots – GitHub


■EventMachine
EventMachineというサイバーパンクな名前のライブラリがRubyにあって、これを使うと並行処理が簡単に書けた。
skype socket gatewayでは
  • 標準入力をSkype APIとして実行する
  • 接続してきたTCP Socketクライアントそれぞれからの入力をSkype APIとして実行し、結果をそれぞれに返す
  • 全ソケットクライアントに全chat logを送る
  • クライアントが接続されているかたまに確認する
という処理をやっていて、これらを適当にEventMachine::defer doの中でloopで書いてやればうまく動いた。

不思議だったのは、新しくacceptしたsocket clientオブジェクトそれぞれを個別に処理するためにEventMachine::deferの中でclient毎にそれぞれEventMachine::deferを作ってみたら、ちゃんとスコープが別になってくれた。
  EventMachine::defer do
loop do
s = sock.accept
clients << s
puts "--- new client : #{clients.size}"

# socket -> invoke Skype API
EventMachine::defer do
loop do
cmd = s.gets
next if cmd == nil or cmd.to_s.size < 1
puts "recv => #{cmd}"
begin
p res = {
:type => 'api_response',
:body => skype.invoke(cmd).to_s
}
rescue => e
res = {
:type => 'error',
:body => 'skype api invoke error'
}
STDERR.puts e
end
begin
s.puts "\n"+res.to_json
rescue => e
STDERR.puts e
c.close
break
end
end
end
end
end


それぞれのdeferの中でAPI呼び出しと結果を返す処理が動いている。これをthreadでやる時
Thread::start(s) do |s|
loop do
res = s.gets
# 何か処理
s.puts response.to_json
sleep 0.01
end
end
みたいに引数に渡さなくても勝手にスコープ分けてくれてた。


でも、clientの配列とかchatメッセージのqueueを作って複数のEventMachine::deferからdeleteしたりpushしたりしていじっている部分では、defer間で共有されていた。不思議だ。
EventMachine::run do
# forward all skype chats -> socket
EventMachine::defer do
loop do
if chat_msgs.size > 0
msg = "\n"+chat_msgs.shift.to_json
clients.each{|c|
begin
c.puts msg
rescue => e
STDERR.puts e
end
}
end
end
end

# check clients connection
EventMachine::defer do
loop do
msg = ''
errors = Array.new
clients.each{|c|
begin
c.puts msg
rescue => e
STDERR.puts e
errors << c
end
}
errors.each{|c|
clients.delete(c)
c.close
}
sleep 15
end
end

よくわからないけどEventMachineが凄い。