い、い、、いっくし!!

各記事はkwskってコメントすると詳しく書き直します

### LINE Message APIとGoogle Apps Scriptで毎朝おはよーしてくれる奴

LINE Message APIGoogle Apps Scriptで毎朝おはよーしてくれる奴

Message APIのセットアップはいろんなサイトで詳しく書いてあるので割愛してGoogle Apps Script (以下GAS)側だけ記載 GASはログ周りが使いにくいのでGoogle Document上にログを出力するオブジェクトの作成

 

var LOGGER = function (TAG) {
  const self = this;
  const fileId = 'Google DocumentのID';

  const file = DocumentApp.openById(fileId);
  const body = file.getBody();
  const tag = TAG;

  const levels = 'newidv';
  this.level = 3;

  const put = function (level, object) {
    if (self.level < levels.indexOf(level)) return;

    const text = typeof object === 'string' ? object : JSON.stringify(object);
    const datetime = JSON.stringify(new Date()).substring(1, 20);
    body.appendParagraph('[' + datetime + '] (' + tag + ') ' + level.toUpperCase() + ': ' + text);
  };

  [].map.call(levels, function (level) {
    self[level] = function (object) { return put(arguments.callee.level, object); };
    self[level].level = level;
  });
};

ほんとはLoggerとしたかったんだが、名前がかぶるので、とりあえず大文字で妥協。 ちなみにconst LOGGER = ほにゃららとすると、エラーで動かない。GASのスコープと初期化のタイミングの問題?

LOGGERオブジェクトは以下のように使える

const log = new LOGGER('Main process');
log.i('処理開始します。');
log.e('エラーです。');

本題、LINEでメッセージのパース、送信をするオブジェクトの作成

var Line = function () {
  const log = new LOGGER('LINE');
  log.v('Create Line Object');
  
  const self = this;
  const ACCESS_TOKEN = 'アクセストークン';
  const OWNER = '自分のID';
  
  self.Info = function (userId) {
    const url = 'https://api.line.me/v2/bot/profile/' + userId;
    const response = UrlFetchApp.fetch(url, {
      headers: { Authorization: 'Bearer ' + ACCESS_TOKEN }
    });
    log.v('Info: ' + JSON.stringify(response));
    const responseContent = response.getContentText();
    log.v('Info: ' + JSON.stringify(responseContent));
    return JSON.parse(responseContent);
  };

  self.Parse = function (contents) {
    log.v('Parse-Start;');
    return contents.events.map(function (lineEvent) {
      log.v('Parse: ' + JSON.stringify(lineEvent));

      const token = lineEvent.replyToken;
      if (typeof token === 'undefined') return undefined;

      const message = lineEvent.message.text;
      const id = lineEvent.source.userId;
      const name = self.Info(id).displayName;
      
      return { message: message, id: id, name: name, token: token };

    }).filter(function (x) { return x; });
  };
  
  self.Send = function (message, reply) {
    log.v('Send: ' + message + ' -> ' + (reply ? reply : 'Owner'));
    const url = 'https://api.line.me/v2/bot/message/' + (reply ? 'reply' : 'push');
    
    const payload = {
      messages: (
        message instanceof Array ? message.filter(function (v, i, a) { return i < 5;}) : [message]
      ).map(function (text) { return { type: 'text', text: text}})
    };
    if (reply) payload.replyToken = reply; 
    else payload.to = OWNER;
  
    return response = UrlFetchApp.fetch(url, {
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
        Authorization: 'Bearer ' + ACCESS_TOKEN,
      },
      method: 'post',
      payload: JSON.stringify(payload),
    });
  };

  self.get = function (url) {
    return response = UrlFetchApp.fetch(url, {
      headers: { Authorization: 'Bearer ' + ACCESS_TOKEN },
      method: 'get',
    });
  };
};

単純にテキストメッセージを送るときはこう

const line = new Line();
line.Send('おはよー');

これを適当な関数に突っ込んでトリガー設定しておしまい。 毎朝「おはよー」ってLINEでメッセージが届く生活が体験できる。

javascript 秘書 Android ファイル構成

APIドキュメントはこちら

 

秘書ファイルの読み込み方は下記の3つがあります。

 

1. 初期秘書ファイル

2. ZIPファイル

3. HTMLファイル(及び構成ディレクトリ)

 

1. 初期秘書ファイル

こちらはリソース埋め込みなので変更することはできません。

主に、初期設定用のチュートリアルにしようと考えています。

 

2. ZIPファイル

自分で作成した秘書ファイルをZIPにまとめて配布するときなどにご利用ください。

中のデータが容易に抽出できないような仕組みを考えています。

 

ファイル構成

FileName.zip

 ├FileName.html

 └image ディレクトリなど

 

必ずZIPファイルと読み込むべきHTMLファイルは同じ名前にしてください。

imageディレクトリなど必要なリソースは相対パスで指定することができます。

 

3. HTMLファイル

各アプリ用のディレクトリに配置することで読み込むことができます。

具体的には

/storage/sdcard0/Android/data/net.halzion.secretary/files/secretary/

などのディレクトリになります。

直下に、該当のHTMLファイルを保存してください。

 

 

javascript 秘書 Android ドキュメント

これ、タイトル詐欺な内容ですね。

www.nicovideo.jpこれの秘書スクリプトのドキュメントです。

 

ファイル構成はこちら

 

概要

Android アプリ側 → 秘書スクリプトの関数呼び出し

秘書スクリプト → window.Seretaryオブジェクトでアプリ側のメソッド呼び出し

 

アプリ側API(古)

こちらは、複数秘書対応前のものです。

そのうち使えなくなる可能性があります。

Initialize(String backgroundImage, String characterImage, String voiceParameter);

message(String text, String voice, boolean playVoice);

 

アプリ側API(新)

Initialize(backgroundImage);

背景画像をセットします。

backgroundImage: 背景画像への相対パス

 

addSecretary(id, image, voiceParameter, position, animation);

秘書を追加します。

- id: 追加する秘書のIDを指定。addSecretary以降、秘書の行動を指示するときに、このIDを利用します。

- image: 秘書画像への相対パス

- voiceParameter: 音声を決めるパラメーター ex) jp.kddilabs.n2tts/ja_JP_fb001

- position: "left" or "right"

- animation: "bottom", "side" or "none"

 

message(id, text, voice, playVoice);

秘書がしゃべります。

- secretaryId: addSecretaryした時に指示したID

- text: 吹き出しに表示されるテキスト

- voice: 発声させるテキスト

- playVoice: true or false. 発声させるか否か。voiceに""を指定した時も、発声はしなくなりますが、ミュートの切り替えなどに利用する想定

 

setConsoleVisibility(visible);

コンソールウィンドウの表示、非表示の切り替え

- visible: 表示するならtrue, 非表示ならfalse, "full"でフル画面表示

  fullモードはcanvasで複雑な描画がしたい時などにご活用ください。

  なお、trueとfullモードでZオーダーが変わります。

 

showToast(text);

Toastを表示します。

- text: 表示するテキスト

 

setButtonImage(place, image);

3つのコントロールボタンを表示します。

- place: "left", "center" or "right"

- image: ボタンイメージへの相対パス

 

intent(url);

intent(packageName, activityName);

インテントを発行します。ざっくり言えば、他のアプリを起動します。

- url: インテントに関連づいたURL

- packageName: org.mozilla.firefoxなどパッケージ名

- activityName: MainActivityなどアクティビティ名

 

setIntent(place, packageName);

ボタンが押された時にインテントを発行するように設定します。

- place: "left", "center", or "right"

- packageName: org.mozilla.firefoxなどパッケージ名

 

version()

現在のJavascriptInterfaceのバージョンを取得します。

今のところ正確なバージョンは取得できません。

 

reload()

秘書ファイルをリロードします。

 

waitSpeak()

しゃべり終わるのを待ちます。

※通常はmessage発行後、しゃべり終わるのを待たずに次の処理に移ります。

 一方、messageを連続して発行した時は、しゃべる内容はキューイングされます。

 

stopSpeak()

喋っている時にしゃべるのを中断します。

 

sleep(millis)

一定時間、スリープします。

- millis: スリープする時間をミリ秒で指定します。

 

なおLocalStorageはHTML5の標準機能ですので、詳しい仕様はHTML5の仕様を参照してください。

 

スクリプトがアプリ側から呼び出される関数

function idle(); 3分間、操作がなかった時に呼び出される。

function left(); 左のコントロールボタンを押した時に呼び出される。

function center(); 真ん中の〃

function right(); 右の〃

 

サンプル

準備中

動画投稿

というわけでニコニコに動画投稿しました。

 

www.nicovideo.jp

アプリ開発はちまちまとやってますが、自分専用ではなく他者にも使ってもらいたいというアプリは中々作れないですね。

 

このブログもそうですけど、情報発信する場があるというのは素晴らしいと思います。

まぁ、PVみてれば発信しても受け取られてないことはわかりきっていますが。

 

ニコニコとの連携で少しでもPV&再生も伸びればいいなっていうそんな下衆い作戦です!!

 

---------- 追記 -------------------

part2投稿しました。

www.nicovideo.jp

作りたい形が見えてきたとこですが、

これ常用するの恥ずかしいな!

シン・ゴジラ

を見ました。

普段は映画はおろかテレビもロクに見ないので、映画館まで見に行ったのは4年ぶりくらい

 

それでもわざわざ映画館に見に行ったのは、単純にエヴァファンっていうのと、これは映画館じゃないと迫力が伝わらないだろうなと思ったから

 

ストーリーとしては、最初から最後までクライマックスって感じで、構成はラミエルが侵略してきてからヤシマ作戦完遂までに似ているんじゃないかな。

ゴジラの登場に慌て、対策する「日本政府」はどこか踊る大捜査線を思わせるようで、エヴァの影響を受けた踊るを更に昇華させて、現実味・迫力・滑稽さをとてもうまくミックスさせていると感じた。

 

前半は庵野さんの趣味全開、後半は別の方が脚本を書いたんじゃないかって思えるくらい仕事としての映画作りのようにも見える。

 

普段感想なんて書かないから、うまくまとまりませんが、エヴァファンにもそうでない人にもおすすめの作品です。

あまり小難しく考えず、単純に怪獣映画として楽しむのがいいと思う。

見ようか迷っている方は是非、映画館で!

ドキュメントスキャナーを買ったら捗る

スキャナーを買った

A4サイズくらいの大きくてぱたんって閉じるやつではなくて

ADFとよばれる紙送り機能の付いている奴。

高い。

 

 

BROTHER ドキュメントスキャナー JUSTIO ポータブルタイプ ADS-1500W

BROTHER ドキュメントスキャナー JUSTIO ポータブルタイプ ADS-1500W

 

 

2013年式を3年落ちで買うのに少し、躊躇したがとても良い買い物だった。

うちには、NASサーバーを設置しているので折角だからPCやスマホと接続せずに直接NASに保存したかった。

いろんなメーカーを調べてみたが、購入前から明確に直接保存できることがわかったのはこの機種だけだった。

 

FTPサーバーを立てとけば、直接保存できるらしい。NASと言わず、クラウドストレージにも保存できそうで、この機能はかなりおすすめ(分かる人には)

HTTPサーバ連携しておけば、セブンで直接印刷なんかもできそう。

 

読み取り速度については、ちょっと不満。読み込んだ後の保存(?)に少し時間がかかる。

用途は、主に明細や名刺などの紙の削減なのでまぁいいだろう。

自炊を主にする人にはやはりScanSnapの方をおすすめする。

 

 

富士通 FUJITSU ScanSnap iX500 (A4/両面/Wi-Fi対応) FI-IX500A

富士通 FUJITSU ScanSnap iX500 (A4/両面/Wi-Fi対応) FI-IX500A

 

 

高いと思うなら、業者に頼むほうがいいだろう。

 

いずれにしろ、紙がへると部屋の清潔感が上がる。誇りが少なくなる。「捨てられない」観念からの脱却と整理整頓にはいい傾向だ。

そのためにも、手間なく紙をデータ化できる環境づくりがみそだと思う

朝シャンから夜シャン派になる10の理由

  1. 朝シャン派は布団が黄色い
  2. ゝは水虫(他白癬菌持ち)
  3. ゝは乾燥肌
  4. ゝは花粉症になりやすい
  5. ゝはフケ、抜け毛が多い
  6. ゝは遅刻が多い
  7. ゝは休みがち
  8. ゝは色欲
  9. ゝは遊び人
  10. ゝは思いやりが少ない

ちゃんちゃん