Alexaに頼むとFANZAから動画を検索してくれるやつ(Alexa SDK V2で)

こんばんは、さっきまでAVでVJしたいなと思ってFANZAでWEBスクレイピングしたりサンプル動画を無限に取得してました。
<img width="1434" alt="スクリーンショット 2018-12-06 7.12.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/a1de4764-f91e-be6f-2dd6-9c72a57076e1.png">

これを応用して、

Alexa、キーワードのえっちぃ動画を紹介してと頼んだら紹介してくれるやつを作ります
書きながら作ります。ほんとはdialogflowとgoogle homeでやりたいところですが
google homeをもっていませんのでAlexaでやります。誰かください。
せっかくなのでAlexa SDK V2で作ります。
あとなんか久々にlambdaを触ったらレイヤー機能というものがあったので使います

##Lambda関数を作ろう
どうやらSDKV2はローカルに落としてきて、入れてあげないといけないみたいです。
なのでとりあえず設計図からalexa-skill-kit-sdk-factskillを選んで
こんな感じでlambda関数を作成します。
<img width="1188" alt="スクリーンショット 2018-12-05 22.58.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/c6cdfc2b-6a8b-0094-f52e-8416bed77f60.png">

##SDKV2を入れよう（レイヤーを使って）
Lambdaにいつのまにか登場していたレイヤー機能がすごい便利！！
他の関数から呼び出せる関数みたいなイメージです。
これさえあれば10MB制限でインラインエディタ使えないみたいなこともない！！
ということでSDKV2レイヤーを作ります

```
$ mkdir sdkv2
$ cd sdkv2
$ yarn add ask-sdk
$ cd ..
$ zip -r nodejs.zip nodejs
```
というZIPを作成し
Lambda > layer > レイヤーの作成

<img width="866" alt="スクリーンショット 2018-12-06 6.36.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/7482ee1e-1545-0f7b-4a00-dcaa9aae4181.png">

**リクエストモジュールも使うのでついでにリクエストモジュールレイヤーも作っておいてください**

```基本関数.js
const alexa = require('ask-sdk');
const request = require(`request`);
//const iconvLite = require('iconv-lite');

let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = alexa.SkillBuilders.custom()
        .addRequestHandlers(LaunchRequestHandler,SerchHandler)
        .create();
    }
    return skill.invoke(event);
}

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder
            .speak('ウェルカム！')
            .getResponse();
    }
};
```

テンプレートテストから Alexa Start Session を選択し、実行してみよう！

<img width="594" alt="スクリーンショット 2018-12-06 6.42.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/76ba6554-8786-532a-300f-92cdd32f08c4.png">
**動いた!!**



#Alexaのスキルを作ります
<img width="977" alt="スクリーンショット 2018-12-06 6.44.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/1c3bfade-8c61-6ff9-552e-466e2ad08e53.png">

こんな感じのインテントを作ります。
searchqueryを使いたかったのですが、日本語対応してないみたいでビルドエラーおきたのでactorで妥協・・・

エンドポイントの設定とかはググってください

#FANZA APIを使おう

<img width="730" alt="スクリーンショット 2018-12-06 7.03.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/23fb28ca-e4c5-5a79-d075-34f4f634784e.png">

FANZAのAPIめちゃくちゃ充実してて、適当にリクエスト投げてあげるだけでなんでもできちゃいます。
アフィリエイトIDが必要なので、取得して使ってみてください


#できた

<img width="392" alt="スクリーンショット 2018-12-06 7.00.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/243994/79ca7d62-4b6f-3b7e-58e7-e3893dd4d2c3.png">

現状キーワード検索して一番上をひっぱってきてるだけです。
echobotディスプレイに対応したりLINEにサンプル動画送ってくれたり、次へっていったら次の動画になったりしたかったのですが、それはおいおい

最終的なコードです。

```index.js
const alexa = require('ask-sdk');
const request = require(`request`);
//const iconvLite = require('iconv-lite');

let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = alexa.SkillBuilders.custom()
        .addRequestHandlers(LaunchRequestHandler,SerchHandler)
        .create();
    }
    return skill.invoke(event);
}

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder
            .speak('ウェルカム！')
            .getResponse();
    }
};

const SerchHandler = {
    //サーチハンドラ
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'FANZAintent';
    },
    handle(handlerInput) {
        //console.log(handlerInput.requestEnvelope.request.intent.slots.actor.value)
        let keyword = handlerInput.requestEnvelope.request.intent.slots.actor.value
        const opts = {
            url: "https://api.dmm.com/affiliate/v3/ItemList?api_id=" + process.env.APPID + "&affiliate_id=" + process.env.AFFILIATEID + "&site=FANZA&service=digital&floor=videoa&hits=1&sort=date&keyword=" + encodeURIComponent(keyword) + "&output=json",
            headers: {
                "Content-type": "charset=UTF-8",
            },
            json: true
        }
        //この辺から検索
        return new Promise((resolve, reject) => {
            doRequest(opts).then((body) => {
                if(body.result.items[0].title != undefined){
                    var title = body.result.items[0].title
                    console.log(title)
                    resolve(handlerInput.responseBuilder
                        .speak(title)
                        .getResponse())
                }
                else{
                    reject(handlerInput.responseBuilder
                        .speak('取得できませんでした')
                        .getResponse())
                }
            })
        })
    }
}

//resolve返せるリクエストにしてあげる関数
function doRequest(options) {
  return new Promise(function (resolve, reject) {
    request(options, function (error, res, body) {
      if (!error && res.statusCode == 200) {
        resolve(body);
      } else {
        reject(error);
      }
    });
  });
}
```

SDK V1 では以下のようにインテントごとに処理をしていましたが

```node.js
const handlers = {
    'hogeintent' : function() {
        //hogehoge
    },
```

V2では各ハンドラの入り口で処理をするみたいです

```node.js
const hogeIntentHandler = {
    canHandle(handlerInput) {
        // インテント名がhogeIntentの時に処理する
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'hogeIntent';
    },
    handle(handlerInput) {
        // 処理の内容
    }
};
```

利点として同一インテント名に対するハンドラをまとめて処理できたり、処理わけが簡単だったりします。

[日本語Alexa] Alexa SDK for Node.js Ver2入門（その１）はじめの一歩
https://dev.classmethod.jp/cloud/alexa-sdk-v2-first/

が参考になりました。

#まとめ
IoTじゃなくてVUIになってしもた