LoginSignup
7
2

More than 1 year has passed since last update.

[GoogleAppsScript] Qiita記事のアクセス数をLINEに通知する

Last updated at Posted at 2021-12-16

はじめに

LINE Notifyを使用してQiita記事のアクセス数(QiitaView)を通知するBOTを作成しました。
1.png

GoogleAppsScript(GAS)にて1日1回通知プログラムを実行します。そのプログラムでは、Qiita APIからその日のアクセス数を取得して、LINE Notifyに通知します。

機能としては下記の通りです。

  • 当日分の記事アクセス数をランキング形式で通知する。
  • 累計アクセス数を棒グラフ画像を通知する。

LINE Notify

GoogleAppsScript

  1. GoogleAppsScriptを開いて、以下のスクリプトを実装します。LINE_NOTIFY_TOKENにLINE Notifyで発行したトークンを指定する。
  2. SSID_QIITA_VIEWにスプレッドシートのIDとSSN_QIITA_VIEWにシート名を指定する。
  3. QIITA_TOKENにQiita APIで発行したトークンを指定する。
main.gs
/**
 * QiitaViewBOT
 */
const LINE_NOTIFY_TOKEN = '*****'; // LINE NOTIFYのアクセストークン
const SSID_QIITA_VIEW = '*****'; // QiitaのスプレッドシートのID
const SSN_QIITA_VIEW = 'QiitaVIEW'; // Qiitaのスプレッドシートのシート名
const QIITA_TOKEN = '*****'; // Qiitaトークン
const TITLE_MAX_LENGTH = 40; // 記事タイトル最大長
const WEEKDAY = ["", "", "", "", "", "", ""];

let spreadsheet = SpreadsheetApp.openById(SSID_QIITA_VIEW);
let sheet = spreadsheet.getSheetByName(SSN_QIITA_VIEW);

/**
 * メイン処理
 */
function main() {
    try {
        addViewCount();

        let itemList = getItemList();

        for (let i in itemList) {
            let item = itemList[i];
            item.increase = 0;
            if (0 < item.list.length) {
                let list = [].concat(item.list);
                item.increase = list.pop().viewCount - list.pop().viewCount;
            }
        }

        itemList.sort((a, b) => {
            return (a.increase > b.increase) ? -1 : 1;
        });

        let nowDt = new Date();
        let dt = Utilities.formatDate(nowDt, 'Asia/Tokyo', `MM/dd(${WEEKDAY[nowDt.getDay()]})`);
        let message = `\n今日のQiitaViewだよ!!\n\n--- ${dt} ----\n\n`;
        for (let i = 0; i < 5; i++) {
            let item = itemList[i];
            let list = [].concat(item.list);
            let data = getQiitaItem(item.id);
            message += `${parseInt(i) + 1}: +${item.increase} (${list.pop().viewCount} views)\n`
            message += `${omit(data.title)}\n\n`;
        }

        let range = sheet.getRange(sheet.getLastRow(), 2, sheet.getLastRow(), sheet.getLastColumn());
        let chart = sheet.newChart().addRange(range).setChartType(Charts.ChartType.COLUMN).setOption('title', 'QiitaViews').build();
        let imageBlob = chart.getBlob().getAs('image/png').setName(`chart.png`);

        console.log(message);
        sendLineNotify(message, imageBlob);

    } catch (e) {
        console.error(e.stack);
    }
}

/**
 * Qiita View数を取得して、スプレッドシートに保存する
 */
function addViewCount() {
    let idList;
    let lastRow = sheet.getLastRow();
    if (0 < lastRow) {
        idList = sheet.getRange(1, 2, 1, sheet.getLastColumn()).getValues()[0];
    }

    let timestamp = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd');
    let viewCountList = [timestamp];
    let itemList = getQiitaItemList();
    let addCount = 0;
    let lastColumn = 0;
    if (0 < lastRow) {
        lastColumn = sheet.getLastColumn() - 1;
    }

    for (let i in itemList) {
        let item = itemList[i];
        item = getQiitaItem(item.id);

        let index = 0;
        let isExist = false;

        if (0 < lastRow) {
            for (let j in idList) {
                let id = idList[j];
                if (id == item.id) {
                    isExist = true;
                    index = parseInt(j);
                }
            }
        }
        if (!isExist) {
            index = lastColumn + addCount;
            addCount++;
        }
        sheet.getRange(1, (index + 2)).setValue(item.id);
        viewCountList[index + 1] = item.page_views_count;
    }
    sheet.appendRow(viewCountList);
}

/**
 * スプレッドシートのデータを取得する
 */
function getItemList() {

    let itemList = [];
    let lastRow = sheet.getLastRow();
    let lastColumn = sheet.getLastColumn();
    let rowList = sheet.getRange(1, 1, lastRow, lastColumn).getValues();

    for (let i = 1; i < lastColumn; i++) {
        let id = rowList[0][i];
        let viewList = [];

        for (let j = 1; j < lastRow; j++) {
            viewList.push({
                createDt: rowList[j][0],
                viewCount: rowList[j][i]
            });
        }
        itemList.push({
            id: id,
            list: viewList
        });
    }
    return itemList;
}

/**
 * 文字列を省略する
 * @param {String} str 
 */
function omit(str) {
    if (TITLE_MAX_LENGTH < str.length) {
        return str.slice(0, TITLE_MAX_LENGTH) + '...';
    } else {
        return str;
    }
}

/**
 * ユーザー記事一覧を取得する
 * @return JSON
 */
function getQiitaItemList() {
    let url = `https://qiita.com/api/v2/authenticated_user/items?page=1&per_page=100`;
    let options = {
        'method': 'get',
        'headers': {
            'Authorization': `Bearer ${QIITA_TOKEN}`
        },
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}

/**
 * ユーザー記事を取得する
 * @param {String} id
 * @return JSON
 */
function getQiitaItem(id) {
    let url = `https://qiita.com/api/v2/items/${id}`;
    let options = {
        'method': 'get',
        'headers': {
            'Authorization': `Bearer ${QIITA_TOKEN}`
        },
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}

/**
 * LINEにメッセージを送信する
 * @param {String} message メッセージ
 * @param {Object} blob 画像ファイル
 */
function sendLineNotify(message, blob) {
    let url = 'https://notify-api.line.me/api/notify';
    let options = {
        'method': 'post',
        'headers': {
            'Authorization': `Bearer ${LINE_NOTIFY_TOKEN}`
        },
        'payload': {
            'message': message,
            'imageFile': blob
        }
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}
  • addViewCount関数では、記事一覧を取得してから、記事詳細を取得しています。スプレットシートに累計アクセス数を保存します。
  • main関数では、スプレットシートから取得した当日と前日の累計アクセス数から、当日分のアクセス数を算出します。昇順に並び替えて上位5件を纏めます。累計アクセス数の棒グラフ画像を作成します。

参考リンク

さいごに

ソースコードをGitHubに公開しています。

以上です。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2