TwitterのbotをGaucheで書き直してみた
「ニコニコ動画にVOCALOIDオリジナル曲の動画が投稿されたのをお知らせする」という、Twitterのbotを去年の12月ごろに作ったので、それをGaucheで書き直してみました。
「こんなbot公開していいのか」と怒られそうなほど欠陥だらけですが・・・
実は、自分でニコニコ動画のRSSを読んでいるわけではなく、VOCALOIDオリジナル曲の新着動画を表示してくれるサイトの「ぼかにゅー」というところのAtomフィードを読んでいます。
(ぼかにゅーの開発者の方には許可取ってるつもりですが・・・)
一応、ぼかにゅーのURLを書いておきます。
ぼかにゅー: http://vocanew.naniyueni.org/
ぼかにゅー開発ブログ: http://d.hatena.ne.jp/vocanew/
一応、Twitter ID「@vnewsong」で動いています。
まず、書き直す前の、Ruby版のコードを出しておきます。
=begin VOCALOID新曲通知TwitterBot VOCALOIDの新曲を10分ごとにチェックしTwitterに投稿する。 新曲情報の入手は「ぼかにゅー」(http://vocanew.naniyueni.org/)から。 =end require "socket" require "net/http" require "rexml/document" require "kconv" require "uri" user = "username" pass = "password" interval = 60 * 10 #10分 lastSongURL = "" #前回取得時点での最新の曲のURL #「ぼかにゅー」の新着情報(Atom)を読み込む def vocanewLoad atom = "" req = Net::HTTP.start("vocanew.naniyueni.org", 80) {|http| res = http.get("/newsong", {"User-Agent" => "vnewsong"}) atom = res.body } return atom end #Twitterに投稿 def tweet(text,username,password) encodedText = URI.encode(text) req = Net::HTTP::Post.new("/statuses/update.json") req.basic_auth username,password req.body = "status=" + encodedText Net::HTTP.start("twitter.com", 80) {|http| res = http.request(req) } end t = Thread.new do #telnetを使って外部から終了させられるようにするサーバー serverSock = TCPServer.open(44444) while true Thread.start(serverSock.accept) do |s| while command = s.gets if command == "stop\r\n" || command == "stop\n" exit break end s.puts "プログラム停止: Command \"stop\"\r\n" end s.close end end end while true #puts "Loading Vocanew Atom Data..." vocanewAtomElems = REXML::Document.new(vocanewLoad).elements songName = vocanewAtomElems["feed/entry/title"].text songURL = vocanewAtomElems["feed/entry/link/@href"].to_s if songURL != lastSongURL #puts songName.tosjis #puts songURL tweet "" + songName + " " + songURL + " #nicovideo", user, pass #puts "Tweet success." #puts "" + songName + " " + songURL lastSongURL = songURL end sleep interval end
実は、かなり適当な作りなので、「取得できていない」ということや、「いつのまにか停止している」ということが何度も起きてしまいます。
「telnetでlocalhostのポート44444に接続して『stop』と入力するとbotを停止できる」という謎の機能がついていますが、
Windows版のGaucheではマルチスレッドが使えないようなので、その機能はGauche版では実装できませんでした。
Gauche版のコードも書いておきます。
; ニコニコ動画に投稿されたVOCALOIDの新曲を通知するTwitter bot ; 情報は「ぼかにゅー」http://vocanew.naniyueni.org/ から取得。 (use rfc.http) (use rfc.uri) (use rfc.base64) (use sxml.ssax) (use sxml.sxpath) (use srfi-1) ; Twitter IDとパスワード (define username "username") (define password "password") ; 読み込む間隔(60秒 * 10 = 10分) (define interval (* 60 10)) ; atom形式のXMLからエントリーのtitleとlinkのリストを取得 (define (get-title-and-link atom) (let ((sxml (ssax:xml->sxml (open-input-string atom) '((feed . "http://www.w3.org/2005/Atom"))))) (zip ((sxpath '(feed:feed feed:entry feed:title *text*)) sxml) ((sxpath '(feed:feed feed:entry feed:link @ href *text*)) sxml)))) ; http://vocanew.naniyueni.org/newsong(ぼかにゅーのAtom)を読み込む (define (load-atom) (values-ref (http-get "vocanew.naniyueni.org" "/newsong" :user-agent "vnewsong") 2)) ; Twitterに投稿する (define (twitter-update status username password) (http-post "twitter.com" (string-append "/statuses/update.json?status=" (uri-encode-string status)) "" :Authorization (string-append "Basic " (base64-encode-string (string-append username ":" password))))) ; 無限ループする ; 引数のoldは、最後に取得したatomデータをget-title-and-linkしたもの (define (loop old) (let* ((atom (load-atom)) (entries (get-title-and-link atom))) (begin (if (not (equal? entries old)) (twitter-update (string-append (caar entries) " " (cadar entries) " #nicovideo") username password)) (sys-sleep interval) (loop entries)))) (define (main args) (loop ()))
汚いコードになってしまいごめんなさい。
Twitter投稿は、前に書いたコードのtwitter-update関数をそのまま使っています。(実はTwitter投稿のコードはこのために書きました)
Atomを読むコードも前に書いたコードを少し書き換えただけです。
「取得できていない」などの問題は今度修正するつもりです。
本当にこんな適当なプログラムを公開してもいいんでしょうか・・・