[Azure Functions] GREAT RACE の放送があるかどうか Slack で知らせる

# はじめに

NHK の [GREAT RACE](https://www4.nhk.or.jp/greatrace/) が好きです！つい見ちゃうんですよね。

夜中の枠があったらぼんやり見たいなーと思っていて、いつも番組表をチェックしていたんですが、どうせなら Slack に流してみようかな、と思ったので作ってみました。

# 使ったもの

* C# (Visual Studio 2019)
* Azure Functions (Timer Trigger)
* [NHK 番組表API](https://api-portal.nhk.or.jp/)

# 作り方

## 準備

### API利用登録

NHK 番組表APIの利用には、事前登録が必要です。登録して API KEY を払い出す必要があります。

登録は [こちら](https://api-portal.nhk.or.jp/) から簡単にできますので、やっておきましょう。

### Slack Incoming Webhook の追加

基本的に手順はググってもらえればいくらでも出ると思うので割愛です。URL を使うので控えておきましょう。

## 書く

Visual Studio 2019 であれば、C# の Azure Functions のテンプレートがあるので、それを開いて書き始めれば OK です。

エラー処理等もしておらずデバッグ用途のコードも入っているアレなコードですが、「結構簡単だったよ！」ということが分かってもらえればと。

```Csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;

namespace GreatRaceBot
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static void Run([TimerTrigger("0 0 20 * * *")]TimerInfo myTimer, ILogger log)
        {
            var API_KEY = "<取得した API KEY>";
            var SLACK_WEBHOOK_URL = "<取得した Webhook URL>";

            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            var url = "https://api.nhk.or.jp/v2/pg/list/130/s1/" + DateTime.Now.AddDays(0).ToString("yyyy-MM-dd")
                + ".json?key=" + API_KEY;

            WebRequest request = WebRequest.Create(url);
            Stream response_stream = request.GetResponse().GetResponseStream();
            StreamReader reader = new StreamReader(response_stream);
            string rawdata = reader.ReadToEnd();

            // 無理やりだが要素数を取得
            var line1 = rawdata;
            var line2 = "\"title\":";
            var arr = line1.Split(line2, StringSplitOptions.None);
            var max_count = arr.Length - 1;

            var jsondata = JObject.Parse(rawdata);
            var hoso = false;
            var result = new List<string>();

            // 放送があるかどうか確認
            for (int i=0; i<max_count; i++)
            {
                var title = jsondata["list"]["s1"][i]["title"].ToString();
                if(title.Contains("ＧＲＥＡＴ　ＲＡＣＥ"))
                {
                    hoso = true;
                    result.Add(jsondata["list"]["s1"][i]["start_time"].ToString());
                }
                log.LogInformation($"[Debug] {title}");
            }

            log.LogInformation($"Today's GREAT RACE : {hoso}");

            // Slack への出力準備
            var output = "Today's GREAT RACE : {hoso}";
            var emoji = ":scream:";
            if (hoso)
            {
                output = output + "\n" + $"Time : {result[0]}";
                emoji = ":wink:";
            }

            // Slack に出力する
            var payload = new Payload
            {
                text = output,
                username = "GREAT RACE Bot",
                icon_emoji = emoji
            };

            Send(SLACK_WEBHOOK_URL, payload);
        }

        static void Send(string url, Payload payload)
        {
            var json = JsonSerializer.Serialize(payload);
            var client = new HttpClient();
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var res = client.PostAsync(url, content).Result;
            Console.WriteLine(res);
        }
    }

    public class Payload
    {
        public string channel { get; set; }
        public string username { get; set; }
        public string text { get; set; }
        public string icon_emoji { get; set; }
        public string icon_url { get; set; }
    }
}
```

# 気付き

* C# で JSON を扱うのは、Python に比べるとなかなか使いにくいなと感じました。`Json.NET` を使っていたら、もうちょっと楽だったのだろうか。
* ループ処理させるための要素数はゴリ押しで取っています。API のレスポンスとして `該当番組数` みたいなのが返ってきていると地味に嬉しかったなぁ。
* NHK の番組表APIは、当日分は 5:00 ~ 29:00 (翌日 5:00) が返ってきます。夜中の 1:00 の番組は、日付としては前日分の URL で叩かないと取得できないことに注意です。まぁ、宵っ張りの私には好都合でしたがｗ
* 同日複数枠放送はめったにないので実装しませんでした。まいっか。