AT-Xの新番組情報をLINEに送ってもらう

サンタクロースをいつまで信じていたかなんてことは
たわいもない世間話にもならないくらいのどうでもいい話ですけれども、
もう12月も下旬に入り、いよいよ年越しの準備に入っていく時期になりました。
皆様、いかがお過ごしでしょうか？

僕はアニメの消化に、西へ東への大奔走をしております(家の中で)

##AT-X #とは
スカパーやケーブルテレビ、ひかりTVなどで視聴可能な
有料のアニメ専門チャンネルです。(月約2,000円弱)

放送中のアニメはもちろん、過去のアニメの再放送やOVA、はたまた劇場版の放送など、
アニメ好きには大変重宝するチャンネルとなっています。

さらに1アニメが週に数回放送されるので、リアルタイムでの視聴を見逃してしまった、
あるいは何度も観返すといったことが容易にできる点でもすごくお得です。

##なぜLINEに送るのか
ちょくちょく[AT-X公式サイトの新アニメ情報](http://www.at-x.com/new_arrival)を見てはいるのですが、『うっかり放送開始日を間違えて覚えている or そもそも放送開始日を覚えていない』ということが多々あるんですよね。
そのたびに、
「やれやれ、またやってしまった……」
と、さながらラノベ原作アニメの主人公のように顔に手を当て天を仰いでいるので、
その状況を改善せねばと思った次第です。

で、なんとなくLINEでそういうのを受信したらよくね？とﾃｨﾝｯ！ときたのでLINEにしました。

##なにを取得するか
[AT-X公式サイトの新アニメ情報](http://www.at-x.com/new_arrival)から

- AT-X初公開番組
- OVA・劇場版・etc
- 再放送番組

のジャンル別に

- 画像
- タイトル
- 放送開始日
- 詳細ページへのリンク

を取得してカルーセル表示しようと思います。


##LINE BOTアカウントの作成
[LINE Developer](https://developers.line.me/ja/index.html) からLINE Messaging APIを利用するための新規Channelを追加します。

公式ページの[クイックスタート](https://developers.line.me/ja/docs/messaging-api/getting-started/)がわかりやすいため方法は割愛します。

ワイはこのDeveloper Trialってやつを使うで！！！！~~(PUSHをしたいため)~~しませんでした。

##LINE BOTを動かす環境を用意する
BOTを作った！さぁBOTで遊ぼっと！！

……

まぁBOTを作っただけでは動きませんね。
あなたは、BOTが喜んで動きたくなるような環境を与えてあげなければなりません。

ということで環境を用意してあげます。
BOTはSSLが利用可能であるところじゃないと動かないです。(https:// ってやつ)

###Heroku へ会員登録をする
ということで Heroku というものを使おうと思います。
Herokuは、PaaS(**P**latform **a**s **a** **S**ervice)という、Webアプリ等を構築・稼働させるためのプラットフォームをインターネット経由のサービスとして提供するものの名称で、
雑に言えば、Webアプリ開発から公開までを簡単にできますよってやつ。

SSLも使えるので、ものぐさな僕にぴったりですね！


ということで、[Heroku](https://www.heroku.com/home)へ会員登録をします。
仮登録後に届く確認メールに書かれているURLをクリックして、パスワードを設定すれば会員登録完了！

###Heroku toolbeltのインストール
Heroku をコマンドラインで動かすために [Heroku toolbelt](https://devcenter.heroku.com/articles/heroku-cli)をインストールします。
各環境でのインストール方法が書かれているのでそれに従いましょう。
僕はMacOSなのでHomebrewでインストール！
`$ brew install heroku/brew/heroku`

```
Cloning into '/usr/local/Homebrew/Library/Taps/heroku/homebrew-brew'...
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (8/8), done.
Unpacking objects: 100% (9/9), done.
remote: Total 9 (delta 0), reused 6 (delta 0), pack-reused 0
Tapped 2 formulae (36 files, 23.6KB)
Error: Xcode alone is not sufficient on Sierra.
Install the Command Line Tools:
  xcode-select --install

```

おっふ

`$ xcode-select --install`

をしてからもう一度brewをしませう。

###Herokuへログインする
コマンドライン上からログインします。`heroku login`と打ちましょう。

```
$ heroku login
Enter your Heroku credentials:
Email: myaccount@example.com
Password: **********
Logged in as myaccount@example.com
```

##BOTを作成する
ここから本題のBOTづくりです。

HerokuへはGitでのデプロイとなります。
そのため、まずはローカルリポジトリを作成しましょう。

###ローカルにBOT作成用のディレクトリを作成する

```
$ mkdir heroku-app
$ cd heroku-app 
``` 
###LINE BOT用のSDKをインストールする

便利なSDKが公開されています。
https://github.com/line/line-bot-sdk-php

`$ composer require linecorp/line-bot-sdk`

と打ちましょう。venderディレクトリやらcomposer.jsonやらが生成されます。

(composerについては割愛します。各自調べてね)

###BOT用のファイルを作成する
移動したディレクトリ内にファイルをを作成し、中を書いていきませう。

```php:callback.php
<?php

require_once 'vendor/autoload.php';
require_once 'scraping.php';

use LINE\LINEBot;
use LINE\LINEBot\HTTPClient\CurlHTTPClient;
use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder;
use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselColumnTemplateBuilder;
use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselTemplateBuilder;
use LINE\LINEBot\MessageBuilder\TemplateMessageBuilder;
use LINE\LINEBot\MessageBuilder\TextMessageBuilder;
use LINE\LINEBot\MessageBuilder\MultiMessageBuilder;

define('CHANNEL_ACCESS_TOKEN', 'アクセストークン(管理画面から取得)');
define('CHANNEL_SECRET'      , 'Channel Secret(管理画面から取得)');

define('LIST_NEW'    , 'AT-X初公開番組');
define('LIST_MOVIE'  , 'OVA・劇場版 etc');
define('LIST_REPEAT' , '再放送番組');


// Botの生成
$bot = new LINEBot(new CurlHTTPClient(CHANNEL_ACCESS_TOKEN), ['channel_secret' => CHANNEL_SECRET]);

// リクエストを受け取る
$contents_raw = file_get_contents('php://input');
$contents     = json_decode($contents_raw);
$event        = $contents->events[0];

// テキストメッセージ受信ではない場合は無言を貫くよ
if ($event->type != 'message') {
    exit;
}

// 今月、来月、再来月の文字がどこかにあるなら、それはもういつのアニメを知りたいか言ってるってことなの
$rcv_text = $event->message->text;
if (strpos($rcv_text, '今月') !== false) {
    $lists = Scraping::createNewArrival()->get();
} elseif (strpos($rcv_text, '来月') !== false) {
    $lists = Scraping::createNewArrivalNext()->get();
} elseif (strpos($rcv_text, '再来月') !== false) {
    $lists = Scraping::createNewArrivalFollow()->get();
} else{
    exit;
}

// 送るね
send($bot, $event, $rcv_text, $lists);
exit;



function send(LINEBot $bot, $event, $rcv_text, $lists)
{
    // どんな文章だろうと以下の単語が入っていたら反応するね
    if (strpos($rcv_text, '新') !== false) {
        $columns = makeArrayForCarousel($lists[LIST_NEW]);
    } elseif (strpos($rcv_text, '映画') !== false) {
        $columns = makeArrayForCarousel($lists[LIST_MOVIE]);
    } elseif (strpos($rcv_text, '再') !== false) {
        $columns = makeArrayForCarousel($lists[LIST_REPEAT]);
    } else {
        exit;
    }

    $message_builder = new MultiMessageBuilder();

    $count_text = count($columns) > 0 ? count($columns) . '件あったよ！' : 'なにもなかったよ';
    $message_builder->add(new TextMessageBuilder($count_text));

    $split_list = array_chunk($columns, 10); // 表示件数で分割する
    foreach ($split_list as $list) {
        $carousel = new CarouselTemplateBuilder($list); // 配列からカルーセルを作成する
        $carousel_message = new TemplateMessageBuilder('アニメ一覧', $carousel); // 作成したカルーセルをメッセージ化する

        $message_builder->add($carousel_message);
    }

    $bot->replyMessage($event->replyToken, $message_builder);
}

function makeArrayForCarousel($lists)
{
    $columns = [];
    if (is_array($lists)) {
        foreach ($lists as $list) {
            $action = new UriTemplateActionBuilder("詳細を見る", $list['detail_url']);

            $column = new CarouselColumnTemplateBuilder($list['title'], $list['start_date'], 'https://www.at-x.com' . $list['img_url'], [$action]);
            $columns[] = $column;
        }
    }

    return $columns;
}
```

```php:scraping.php
<?php

class Scraping
{
    public static function createNewArrival()
    {
        return new Create('new_arrival');
    }

    public static function createNewArrivalNext()
    {
        return new Create('new_arrival/next');
    }

    public static function createNewArrivalFollow()
    {
        return new Create('new_arrival/follow');
    }
}

class Create
{
    protected $base_url = 'http://www.at-x.com/';
    protected $data_where;
    protected $data;

    public function __construct($data_where) {
        $this->data_where = $data_where;
    }

    public function get()
    {
        require_once 'phpQuery-onefile.php';

        $html_raw = file_get_contents($this->base_url . $this->data_where);
        $html = preg_replace('/^<\?xml.*\?>/', '', $html_raw);
        $doc = phpQuery::newDocument($html);

        $data = null;
        foreach($doc['#pageProgramDetail .section'] as $section) {
            if (pq($section)->find('h3')->html() === '') {
                continue;
            }

            $section_title = pq($section)->find('h3 img')->attr('alt');
            foreach (pq($section)->find('.newBlock') as $i => $block) {
                preg_match('/■.+■/', pq($block)->find('.right')->text(), $match);
                if (isset($match) && mb_strlen($match[0]) > 60) {
                    $match[0] = '詳細ページで確認してください';
                }

                $data[$section_title][$i] = [
                    'img_url'    => pq($block)->find('.left a img')->attr('src'),
                    'title'      => pq($block)->find('.right h4 a')->text(),
                    'detail_url' => pq($block)->find('.right h4 a')->attr('href'),
                    'start_date' => $match[0] ?: '不定期放送',
                ];
            }
        }

        return $data;
    }
}
```

どんどんコードが雑になっていってるけど、とりあえず動いてるからよしとします。
僕がよしと言ったらよしなのです。

改善点はてんこもりですよ〜
盛るぜ〜超盛るぜ〜

###ローカルリポジトリを作成する
で！

ファイルを作成したディレクトリ上で

```
$ git init
$ git add .
$ git add -m 'First Commit' //コミットメッセージを書く
```

###Herokuにアプリを作成する
Herokuにログインした状態で以下のコマンドを打つ。

```
$ heroku create <アプリ名>  //アプリ名は入れなくても可(後から変更できる)
Creating app... done, ⬢ xxxxxxx-xxxxxxxx-xxxxx
https://xxxxxxx-xxxxxxxx-xxxxx.herokuapp.com/ | https://git.heroku.com/xxxxxxx-xxxxxxxx-xxxxx.git
```

###Herokuで作成されたリポジトリへPushしデプロイする

```
$ git push heroku master
```

###Webhook送信URLを設定する

`$ heroku create` で生成されたURLを管理画面の「Webhook URL」へと登録しましょう。
<img width="435" alt="Webhook登録画像" src="https://qiita-image-store.s3.amazonaws.com/0/140846/03836241-d5df-6f99-f3ad-31715e09bf80.png">

**※Webhook送信を『利用する』にしないとユーザからのリクエストを受信できません**

ちなみに「俺は他のやつからのリクエストなんて受け付けねぇぜ！」っていうロックな人は設定しなくてもおｋです。(Herokuなだけに)

##動かしてみる
![top.png](https://qiita-image-store.s3.amazonaws.com/0/140846/e33897e2-312e-cd4a-da34-52eefcf81cca.png)
かわいいですね

###来月の新放送アニメを取得する
![next_new.png](https://qiita-image-store.s3.amazonaws.com/0/140846/dc9ba14d-e56e-ec11-35b3-86b3b0266240.png)

###来月の映画を取得する
![next_movie.png](https://qiita-image-store.s3.amazonaws.com/0/140846/76c6b7e6-e870-5975-f16e-cfd3254324a9.png)
マスターになりたい
###再来月の再放送を取得する
![follow_repeat.png](https://qiita-image-store.s3.amazonaws.com/0/140846/3e848377-b419-bb5b-f0f1-3dc99132215b.png)
まだなかった

###こういうのにももちろん反応する
![neta.png](https://qiita-image-store.s3.amazonaws.com/0/140846/e538da55-2de1-a337-ad94-b8ccadc80922.png)
かわいい

##まとめ
これでアニメの録り逃しが減ること間違い無し！！

ちょっと色々とぐちゃぐちゃになったのでリファクタリングしたさMAXなのですけれども、

*「年が明けてからじっくりしよう、今年はもういいや」*
そう心にLINEを引く僕なのでした。


####ちなみに
`$ heroku logs --tail`

でherokuのログがストリーミングで見れる

##参考リンク
[PHP版の公式SDKを使ってLINE Messaging APIベースのBotを作ってみた](https://qiita.com/yositosi/items/87a0ee54ab88b934b1cb)
[Heroku初心者がHello, Herokuをしてみる](https://qiita.com/Arashi/items/b2f2e01259238235e187)