0

URLエンコードされた日本語URLをデコードするhubot script

URL 日本語でおk


たまにこういう日本語URLがチャットに貼られて、URLエンコードされていて何がなんだかわからない事があったので対策した。
hubotが日本語に戻してくれる。

そもそもブラウザのURL欄からコピーしたら自動的にエンコードしてくれるのは何でなんだろう、この自動変換があるので日本語ドメイン名とか取る気にならない。



decode-encoded-url.coffee


# Description:
# encodeされたURLを日本語に戻す
#
# Author:
# @shokai

module.exports = (robot) ->

robot.hear /(https?:\/\/[^ ]+)/i, (msg) ->

who = msg.message.user.name
url = msg.match[1]
url_decoded = decodeURI url
return if url is url_decoded
url = url_decoded.replace /[ <>]/g, (c) -> encodeURI c
msg.send "@#{who} 日本語でおk\n#{url}"

スペースと、<と>があるとSlackのURLの自動リンクが付かないのでデコードした後に再コードしてる。

0

tesselでYo

tesselは普通にnpmが使えるので、Yoとかも送れる

ただ、multipart/form-dataがpostできないのであまり大きな通信はできないみたいだけど、Yoぐらいなら簡単に送れる。

まあYo送るのが簡単なのはどうでもよくて、プログラムの中にAPI Tokenなどの設定値を書きたくないけど実行時に渡すようなのは(環境変数とか)tesselではどうやるのかな、というのを調べたりした。


MacからYoを送る


久しぶりにYo見てみたら、Yo Developer Dashboardからアカウントを作ったり、APIのTOKENを取得できるようになってた。以前のように待たされることなくすぐ作れる。

% npm install yo-api -save
% export YO_TOKEN=a1b2c3defg45678

Yo = require 'yo-api'

yo = new Yo process.env.YO_TOKEN

yo.yo_link 'SHOKAI', 'http://shokai.org', (err, res, body) ->
console.log body


tesselからYoを送る

tessel-study/yo at master · shokai/tessel-study

前に書いたように起動してすぐwifiを再起動して、on ‘connect’後にネットワークを使う処理をするようにする。

var tessel = require('tessel');
var wifi = require('wifi-cc3000');
var Yo = require('yo-api');

var yo_token = process.argv[2];
var yo = new Yo(yo_token);

var led_green = tessel.led[0].output(1);
setInterval(function(){
if(wifi.isConnected()) led_green.toggle()
}, 500);

// wifiを再起動
wifi.reset();

wifi.on('connect', function(){
console.log('wifi connect');
yo.yo('SHOKAI', function(err, res, body){
console.log(err);
console.log(body.toString());
});
});


tesselに引数を渡す

普通API Tokenとかはコード中に書きたくないので、環境変数とか設定ファイルに書く。

tesselの場合、実行時の引数に渡せる。
コード中でprocess.argv[2]でyo_tokenを取得しているが、これは

% tessel run main.js $YO_TOKEN
% tessel push main.js --args=$YO_TOKEN --logs

こうするとargvに渡せる。

package.jsonのscriptsに書いておくとnpm testやnpm startで書き込めて便利。
{
"name": "yo",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "tessel run main.js $YO_TOKEN",
"start": "tessel push main.js --args=$YO_TOKEN --logs"
},
"author": "",
"license": "ISC",
"dependencies": {
"wifi-cc3000": "0.0.0",
"yo-api": "^1.0.0"
}
}

bundleFiles関数でtessel上でのコードにprocess.argvが設定されて、この後Luaに変換されてボードに書き込まれる。
これがtessel pushからはargvが渡らないバグがあったので修正したプルリクを送ったらmergeされた。

tessel runでは今のバージョンでもargv渡せる。tessel pushの方はそのうちnpmが更新されて使えるようになるまで待つか、俺のgithubからインストールするとかする。


nomnom

tessel cliではnomnomというoption parserが使われている。

複数のargvを渡す場合、–argsオプションを複数書く。

% tessel push app.js --args=foo --args=bar --args=baz

これでprocess.argvは
["tessel", "app.js", "foo", "bar", "baz"]
になる。

0

OAuth版Gyazo APIのNode.jsラッパー作った

OAuthで使う新しいGyazo APIができてたので、Node.js用のラッパーを作った。今までのupload.cgiにアップロードする奴とは別の最近できたAPIっぽい。


https://www.npmjs.org/package/gyazo-api
https://github.com/shokai/node-gyazo-api

% npm install gyazo-api


アップロード


開発者としてアプリケーションを登録して、Access Tokenを取得してから

こういう風にアップロードできる。
var Gyazo  = require('gyazo-api');
var client = new Gyazo('ACCESS_TOKEN');

client.upload('/path/to/file.jpg')
.then(function(res){
console.log(res.data.image_id);
console.log(res.data.permalink_url);
})
.catch(function(err){
console.error(err.stack);
});
upload関数はファイルパスでなくstreamやbufferも渡せる。

他にアップロードした画像のリストを取得したり、削除もできる。
Gyazo API、response bodyにJSONで結果が返ってくるんだけどHTTP Headerにもx-per-pageとかx-current-pageとかついているので、res.responseにレスポンスオブジェクトそのまま付けておいた。



Travis CIで俺のアイコンをアップロードしたり消したりしているので、テスト実行する度にgyazo.com/historyに俺の写真が上がったり消えたりしててつらい

0

Travis CIに環境変数を設定する

参考

Travis CI: Environment Variables – Secure Variables


環境変数をセット

.travis.yml にenvを設定すれば環境変数がセットされた状態でtestが走る
language: node_js
node_js:
- '0.10'
env:
GYAZO_TOKEN=a1b2cdef123456hogehoge

テストコードの中で使える
gyazo = new Gyazo process.env.GYAZO_TOKEN
gyazo.upload "#{__dirname}/test.jpg"


暗号化

APIのtokenとかを晒したくない場合は

% travis encrypt "GYAZO_TOKEN=a1b2cdef3456asdfhogehoge" --add env

すると”secure: ~~~~”という暗号化された文字列になってenvに追加されて、Travis CIのサーバーで実行時に復号される。

0

hubot-rss-readerにRSSを探す機能を付けた

SlackなどのチャットサービスをRSSリーダーにできるhubotスクリプトであるhubot-rss-readerにRSSを探す機能を付けた

v0.5.3になった。

えらい人のはてブとかを読み込んだチャンネルをSlackにいろいろ作って、それをみんなでウォッチしたりできる。


RSSを探す

RSSではない、ふつうのwebページのURLを追加しようとするとRSSを探すようになった。
nikezono君のfind-rssを使ったら簡単だった。



callbackを全部Promiseで書きなおした


ちゃんとテスト書いてあれば、mochaならcatchを自動的にやってくれるしcallbackからpromiseへの書き直しすんなりできると思う。hubot-rss-readerの他にも1つ全体を書きなおしたのがあるけど特にハマる所は無かった。

bluebirdを使った。
bluebirdはpromisifyAllにオブジェクトを渡すとそれが持っているメソッドを全部Promise化してくれるし、1つの関数だけ提供しているfind-rssなんかもpromisifyでPromise化して使える。

FindRSS = Promise.promisify require 'find-rss'

これが
  robot.respond /rss\s+(add|register)\s+(https?:\/\/[^\s]+)/im, (msg) ->
url = msg.match[2].trim()
last_state_is_error[url] = false
debug "add #{url}"
checker.addFeed msg.message.room, url, (err, res) ->
if err
msg.send err
return
msg.send res
checker.fetch url, (err, entries) ->
unless err
for entry in entries
msg.send entry.toString()
return
msg.send err
if err.message is 'Not a feed'
checker.deleteFeed msg.message.room, url
RSSFinder url, (err, feeds) ->
return if err or feeds?.length < 1
msg.send _.flatten([
"found some Feeds from #{url}"
feeds.map (i) -> " * #{i.url}"
]).join '\n'
return


こう書けてすっきりした
  robot.respond /rss\s+(add|register)\s+(https?:\/\/[^\s]+)/im, (msg) ->
url = msg.match[2].trim()
last_state_is_error[url] = false
debug "add #{url}"
checker.addFeed msg.message.room, url
.then (res) ->
new Promise (resolve) ->
msg.send res
resolve url
.then (url) ->
checker.fetch {url: url, room: msg.message.room}
.then (entries) ->
for entry in entries
msg.send entry.toString()
, (err) ->
msg.send "[ERROR] #{err}"
return if err.message isnt 'Not a feed'
checker.deleteFeed msg.message.room, url
.then ->
FindRSS url
.then (feeds) ->
return if feeds?.length < 1
msg.send _.flatten([
"found some Feeds from #{url}"
feeds.map (i) -> " * #{i.url}"
]).join '\n'
.catch (err) ->
msg.send "[ERROR] #{err}"
debug err.stack