20201120のNode.jsに関する記事は5件です。

YouTubeの配信・動画のコメント(トップレベルコメントのみ)を取得するnode.jsのツールを作成

概要

  • 気になる事があったので、配信のコメントを取得するツールを作成した。
  • トップレベルコメントのみ(コメントへの返信は取得していない)
  • APIキーは伏字。log4jsでログ出力しているので(いないとは思いますが)流用する場合は各々の出力方法に変換してください。

引数

  • 動画ID(watch?v=XXXXXXXXXXXのXXXXXXXXXXX部分)

実行結果

以下を出力する。
- 投稿者表示名(items.snippet.topLevelComment.snippet.authorDisplayName)
- 投稿者チャンネルID(items.snippet.topLevelComment.snippet.authorChannelId.value)
- 表示メッセージ(items.snippet.topLevelComment.snippet.textDisplay)
- いいね数(items.snippet.topLevelComment.snippet.likeCount)
- 投稿日(items.snippet.topLevelComment.snippet.publishedAt)
- 詳細はAPIドキュメントを参照

備考

YouTubeの利用規約としては、個人を特定する情報を収集・取得するのは駄目、とありますが、
APIで取得できる情報が規約的に駄目ならAPIを使っては駄目なのでは、という話になりかねないので
とりあえず取得できるものは見ていい(DBには保存しない)というスタンスで扱います。

ソース

const ApiKey = "key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const UrlCommentThreads = "https://www.googleapis.com/youtube/v3/commentThreads?" + ApiKey + "&part=snippet&maxResults=100&videoId="

var logger  = require('../modules/logger');

var axios = require("axios");

let targetVideoId = getTargetVideoId(process.argv);
if ( targetVideoId == undefined || targetVideoId.length == 0 ) {
  logger.info("video comment require arg... video id.")
  return;
}

// call main
main(targetVideoId);

function getTargetVideoId(argv) {
  if ( argv.length <= 2 ) {
    return "";
  }
  return argv[2];
}

// main
async function main(videoId) {
  logger.info("video comment start");
  var itemArray = new Array();
  logger.info("get video comment, videoId[" + videoId + "]");
  await outVideoComment(itemArray, videoId, "");
  logger.info("video comment end");
};

// out video comment
async function outVideoComment(itemArray, videoId, pageToken) {
  var nextPageToken = "";
  var docs = undefined;
  let requestUrl = UrlCommentThreads + videoId + "&pageToken=" + pageToken;
  logger.debug(requestUrl)
  await axios.get(requestUrl)
        .then(function(res) {
          nextPageToken = res.data.nextPageToken;
          docs = res.data.items;
        })
        .catch(function(err) {
          docs = undefined;
          logger.error("axios error!");
          logger.error(err);
        });

  if ( docs != undefined && docs.length > 0 ) {
    for ( let key in docs ) {
      let topLevelCommentSnippet = docs[key].snippet.topLevelComment.snippet;
      let comment = {
        authorDisplayName: topLevelCommentSnippet.authorDisplayName,
        authorChannelId: topLevelCommentSnippet.authorChannelId.value,
        textDisplay: topLevelCommentSnippet.textDisplay,
        likeCount: topLevelCommentSnippet.likeCount,
        publishedAt: topLevelCommentSnippet.publishedAt
      }
      logger.info(comment);
    }
  } else {
    logger.debug("no docs");
  }
  if ( nextPageToken == undefined || nextPageToken == "" || nextPageToken.length == 0 ) {
    logger.debug("no next page");
    return;
  }
  await outVideoComment(itemArray, videoId, nextPageToken);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【エラーコード別解説】Twitter の Account Activity API の Webhook URL が登録できないときの解決法

はじめに

Twitter の Account Activity API を使う機会があり、こちらの記事 を参考に Webhook URL を登録しようとしたのですが、なかなか登録できず、丸一日ほど費やしてしまいました。

Webhook の登録はかなり罠があり、調べても解決法が全然出てこなかったため、この記事では、発生するエラーコードを紹介し、その原因と解決法について解説します。参考になりましたら幸いです。

正しい設定方法だけ見たい

正しい設定方法

事前準備

Webhook URL を登録する際には POST リクエストを Twitter に送る必要があります。そのリクエストを送るために、本記事では Postman を利用します。あらかじめアカウント登録し、デスクトップ版アプリをインストールしておいてください。

cURL でもできる気がしますが、罠が多すぎていちいちパラメータをいじるのがめちゃくちゃ大変だったので Postman の使用をおすすめします。

アカウント登録

アカウントを持っていない場合は こちら からアカウントを作成してください。

アプリのインストール

アカウント登録またはサインイン後に Workspace に行き、画面右下の Desktop Agent から Download desktop agent をクリックしてダウンロードしてください。
スクリーンショット 2020-11-20 13.22.17.png

または、macOS をお使いの方は Homebrew Cask からインストールすることもできます。

$ brew cask install postman

その後、アプリを起動し、サインインしてください。

アプリをインストールする必要がありますか? ブラウザではダメですか?

Postman は Web 版で使用することもできます。しかし、ブラウザで検証したところ、CORS の制約に引っかかってしまいリクエストを送信することができませんでした。そのためアプリ版を使用する必要があります。

目次

発生したエラーコードの解説だけ知りたい方は以下の目次をご活用ください。

エラーコード 32

エラーメッセージは Could not authenticate you です。「認証できませんでした」ということなのですが、理由が全く書かれていないためこれだけではわかりません。

{
    "errors": [
        {
            "code": 32,
            "message": "Could not authenticate you."
        }
    ]
}

公式のトラブルシューティング を見ても「リクエストの認証データに問題がある」ということしかわからず、認証データの「どこ」に問題があるかはわかりません。
スクリーンショット 2020-11-19 22.44.01.png

ネットで調べてみると、このエラーで苦しんでいる人が多くいるようでした。何を隠そう、自分もこのエラーで苦しみました。

原因

このエラーが発生する原因として考えられるのは、Webhook URL をクエリパラメータとして設定していること です。つまり、リクエストの URL を、以下のように指定しているためです。

https://api.twitter.com/1.1/account_activity/all/:ENV_NAME/webhooks.json?url=https%3A%2F%2Fyour_domain.com%2Fwebhook%2Ftwitter

:ENV_NAME には、設定した Dev environment label が入ります。何を意味しているかわからない場合は「エラーコード 200」の解説をご覧ください。

公式ドキュメント にはクエリパラメータとして Webhook URL を指定する例が載っているのでこれが正しそうな気がしますが、なぜかこれではうまくいきません。

解決方法

これの解決方法は、POST リクエストの Body にこのパラメータを入れること です。つまり、
スクリーンショット 2020-11-20 13.54.52.png
↑ こうではなく
スクリーンショット 2020-11-20 13.56.20.png
↑ こうしてください

Body タブを開き x-www-form-urlencoded を選択して、KEYurlVALUE にあなたの Webhook URL を指定してください。

このときの注意点として、Webhook URL はパーセントエンコーディングしてはいけません。上記の例で説明すると、https%3A%2F%2Fyour_domain.com%2Fwebhook%2Ftwitter ではなく https://your_domain.com/webhook/twitter と記載してください。

エラーコード 261

エラーメッセージは Application cannot perform write actions です。書き込み権限がないというエラーです。

{
    "errors": [
        {
            "code": 261,
            "message": "Application cannot perform write actions. Contact Twitter Platform Operations through https://help.twitter.com/forms/platform."
        }
    ]
}

エラーメッセージに「Twitter プラットフォームオペレータに連絡してください」とありますが、アカウントが凍結したりアプリが停止処理を受けていない限りは連絡しても解決しません。そもそもまだ Webhook URL の登録すらできていないのでアプリが停止処理を受けているなんてことはふつうありえません。

原因

このエラーが発生する原因として考えられるのは、アプリに書き込み権限を与えていないこと です。

解決方法

Twitter Portal Dashboard にアクセスし、アプリの権限を変更してやります。

左カラムの Projects & Apps のタブを開き、使用しているプロジェクトまたはアプリを開き、App permissions を確認します。ここが Read only になっている場合は右上の Edit をクリックして権限を変更します。
スクリーンショット 2020-11-20 14.13.24.png

一番下の Read + Write + Direct Messages を選択して保存します。
スクリーンショット 2020-11-20 14.18.00.png
DM の権限がいらない場合は、おそらく Read and Write でも問題ないかもしれませんが、試していません。少なくとも Read ではダメです。

次に、Keys and tokens のタブをクリックし、Access token & secret の権限を確認します。先ほど App permissionsRead only になっていた場合は、権限修正後もここが Read only になっているかと思います。その場合は Regenerate をクリックしてトークンを再発行します。
スクリーンショット 2020-11-20 14.18.28.png
トークンが変わるので、再度 Webhook URL 登録のリクエストを送る際に忘れずにトークンを変更してください。

エラーコード 89

エラーメッセージは Invalid or expired token です。トークンが無効か期限切れであるというエラーです。

{
    "errors": [
        {
            "code": 89,
            "message": "Invalid or expired token."
        }
    ]
}

原因

おそらくこれは先ほどのエラーコード 261 の解決法の手順でトークンを変更したのを忘れていた場合に発生すると思います。

解決方法

Regenerate を実行したあとはキーやトークンが変わるので忘れずに変更してください。

エラーコード 200

エラーメッセージは Forbidden です。これまたシンプルなメッセージですね。シンプルすぎて原因が不明です。

{
    "errors": [
        {
            "code": 200,
            "message": "Forbidden."
        }
    ]
}

原因

このエラーが発生する原因として考えられるのは、Account Activity API の Dev environment label を、認証しようとしているアプリに紐づけていないためです。何を言っているのかわからないかと思いますのでスクリーンショットで解説します。

解決方法

左カラムの Products のタブを開き、Dev Environments を開きます。すると 3 つの環境をセットできる画面が表示されます。そのうちの Account Activity API / Sandbox の項目を見てください。まだ何も設定していない場合は NOT SET UP と表示されているはずです。その場合は Set up dev environment をクリックし、環境をセットアップしてください。
スクリーンショット 2020-11-20 14.41.17.png

Dev environment labelApp を設定するダイアログが表示されます。Dev environment label には任意の名前、App は使用しているプロジェクトまたはアプリを選択します。
スクリーンショット 2020-11-20 14.42.54.png
Dev environment label は任意と言いましたが、URL の一部となるため、わかりやすい名前にするのが良いです。本番環境で使用するつもりのアプリなら prodproduction、開発環境で使用するつもりなら devdevelopment などです。

とりあえずテストで使うなら test としても良いですが、一度設定してしまうと、あとから環境を作り直しても同じ Dev environment label 名は使用することができない そうなので十分注意してください。

そして、ここで設定した Dev environment label を、Webhook URL を登録する POST リクエストの URL の :ENV_NAME の部分に当てはめます。

https://api.twitter.com/1.1/account_activity/all/:ENV_NAME/webhooks.json

たとえば Dev environment label を prodcution とした場合、

https://api.twitter.com/1.1/account_activity/all/production/webhooks.json

としてください。

エラーコード 357

エラーメッセージは url: queryParam is required です。Webhook URL が設定されていないのが原因です。

原因

このエラーが発生する原因として考えられるのは、主に Webhook URL を指定し忘れているか、指定するキーが間違っていることです。

解決方法

Postman を使用している場合は、Webhook URL のパラメータにチェックが入っていることと、KEY を間違えていないことを確認してください。正しい KEYurl です。
スクリーンショット 2020-11-20 15.35.51.png

エラーコード 34

エラーメッセージは Sorry, that page does not exist です。ページが存在しないというエラーです。

{
    "errors": [
        {
            "message": "Sorry, that page does not exist",
            "code": 34
        }
    ]
}

原因

これはおそらく URL の :ENV_NAME の部分をそのままにしているパターンです。
スクリーンショット 2020-11-20 15.43.06.png

解決方法

:ENV_NAME には Dev environment label を指定します。詳細は「エラーコード 200」の解説を確認してください。

エラーコード 131

エラーメッセージは Internal error です。その名の通り内部エラーです。エラーが発生してエラー内容が「内部エラー」って何かのとんちですかね?

{
    "errors": [
        {
            "message": "Internal error",
            "code": 131
        }
    ]
}

原因

これはおそらく Webhook URL をサンプルのまま書いているパターンです。
スクリーンショット 2020-11-20 16.39.03.png

解決方法

https://your_domain.com/webhook/twitter はあくまで例なので、実際に自分が用意した Webhook URL を使用してください。

エラーコード 214

エラーコード 214 は原因によって 4 種類のエラーメッセージが発生しました。一つずつ解説します。

Unable to connect during CRC GET request

エラーメッセージは Unable to connect during CRC GET request です。「こちらが指定した Webhook URL に Twitter が GET リクエストを送信したところ、GET リクエストが送信できなかった」というエラーです。

{
    "errors": [
        {
            "code": 214,
            "message": "Unable to connect during CRC GET request."
        }
    ]
}

原因

これの原因として考えられるのは、Webhook URL が間違っていて Webhook 先のサーバにアクセスできないということです。Postman で Webhook URL として指定した URL をコピーしてその後ろに ?crc_token=foo とつけてブラウザでアクセスしてください。たとえば以下のような URL です。

https://your_domain.com/webhook/twitter?crc_token=foo

このときブラウザでは以下のように表示されることが期待されます。

{"response_token":"sha256=2rzGn72Vut3ALp+QtkkTgnQ/dE3tmn/HXT+XThpve4B="}

もし Web サイトにアクセスできなかった場合はこのエラーメッセージに該当するはずです。ドメインが間違っていたり、DNS の設定がまだ反映されていなかったり、自分で設定した Webhook 先のサーバがダウンしていたりなどが原因として挙げられます。

Non-200 response code during CRC GET request (i.e. 404, 500, etc)

エラーメッセージは Non-200 response code during CRC GET request (i.e. 404, 500, etc) です。「こちらが指定した Webhook URL に Twitter が GET リクエストを送信したところ、200 OK ではない HTTP ステータスが返ってきた」というエラーです。

{
    "errors": [
        {
            "code": 214,
            "message": "Non-200 response code during CRC GET request (i.e. 404, 500, etc)."
        }
    ]
}

Unable to connect during CRC GET request と同じように Webhook URL の後ろに ?crc_token=foo とつけてアクセスした際に 404 Not Found や 500 Internal Server Error などが表示されるはずです。

原因

おそらくこれは Nginx などの Web サーバの設定が間違っているか、Webhook を受け付けるスクリプトの実装が間違っているかです。どちらもサーバのログを見てエラー内容を調べる必要があります。

参考スクリプト

ぼくが使用した Node.js のスクリプトを載せておきます。Node.js で実装しましたが、他のプログラミング言語でも問題ありません。参考にしてみてください。

index.js
require('dotenv').config();

const express = require('express');
const app     = express();
const port    = 5000;
const crypto  = require('crypto');

app.get('/webhook', (req, res) => {
  console.log('GET /webhook');
  const hmac = crypto.createHmac('sha256', process.env.CONSUMER_SECRET).update(req.query.crc_token).digest('base64');
  res.send('{"response_token":"sha256=' + hmac + '"}');
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});
.env
CONSUMER_SECRET=<YOUR_CONSUMER_SECRET>
command
$ npm init
$ npm install express --save
$ npm install dotenv --save
$ node index.js

事前に Express.js や dotenv のインストールが必要です。また、http://localhost:5000 を Nginx 等でリバースプロキシする必要があります。

Webhook URL does not meet the requirements

エラーメッセージは Webhook URL does not meet the requirements です。Webhook URL が要件を満たしていないというエラーです。

{
    "errors": [
        {
            "code": 214,
            "message": "Webhook URL does not meet the requirements. Please use HTTPS."
        }
    ]
}

原因

主な原因としては 2 つ考えられます。

HTTPS 対応していない

エラーメッセージに Please use HTTPS と書かれていることからもわかる通り、Webhook URL は HTTPS でなければなりません。もし HTTPS になっていない場合は Let’s Encrypt などを使用して HTTPS 対応をしてください。

Nginx + Let’s Encrypt での対応方法については以前に記事にまとめていますので参考にしてください。
Nginx+リバースプロキシ環境でWebサーバを停止させずに Let's Encrypt (Certbot) のSSL証明書を自動更新する

URL の指定方法が間違っている

有効な URL が指定されていないとこのメッセージが表示されます。ご丁寧にも Please use HTTPS と書かれているのが逆にややこしいですが、http:// になっているだけでなく、それ以外の無効な URL だった場合も同様のメッセージなので、正しい URL かどうかを確認してください。

よくありがちなのは、パーセントエンコーディングしてしまっている場合です。「エラーコード 32」のときにも書きましたが、POST リクエストの Body に Webhook URL を含める際に、パーセントエンコーディングしてはいけません。

スクリーンショット 2020-11-20 16.30.29.png
↑ こうではなく
スクリーンショット 2020-11-20 16.31.19.png
↑ こうしてください

Too many resources already created

エラーメッセージは Too many resources already created です。すでに Webhook URL の登録が完了しています。おめでとうございます ?

{
    "errors": [
        {
            "code": 214,
            "message": "Too many resources already created."
        }
    ]
}

補足しておくと、無料版1では 1 つしか Webhook URL を設定することができません

2 つ以上の Webhook URL を登録したかったら 有料版を契約する 必要がありますが、有料版は一番安くても $339 / month (約 35,000 円 / 月)2なので一般人には手が出せませんね……。おそらくこれは企業向けだと思います。

なので、遊びで複数のサービスやアプリを作りたくて、なおかつ Account Activity API を使用する場合は、一つの Webhook URL を使い回すことになります。登録した Webhook URL に Twitter からアクティビティがリアルタイムで届くので、それを受け取るスクリプトを用意しておいて、受け取ったデータを各サービスやアプリにパススルーするような実装になると思います。

正しい設定方法

正しい設定方法でまとめると、以下のようになります。以下は Postman での設定例です。

Authorization

まず Authorization タブを開きます。そして以下の通りにパラメータ等を指定します。
スクリーンショット 2020-11-20 16.47.50.png

番号 補足
POST
Dev environment label に設定した値 詳しくは「エラーコード 200」の解説を参照
OAuth 1.0
Request Headers
Signature Method は HMAC-SHA1 を指定

なお、Consumer KeyConsumer Secret というのは Twitter Developer Portal の画面でいう API key & secret のことです。View Keys をクリックすれば見ることができます。
スクリーンショット 2020-11-20 17.02.05.png
Access token & secret は一度だけしか表示されずあとから見ることができませんので、忘れてしまった場合は Regenerate で再発行してください。

Headers

次に Headers タブを開きます。そして以下の通りにパラメータを指定します。
スクリーンショット 2020-11-20 17.08.39.png

KEY VALUE
Content-type application/x-www-form-urlencoded

これは設定しなくてもうまくいくかもしれません。うまくいかなかったら設定してみてください。

Body

最後に Body タブを開きます。そして以下の通りにパラメータ等を指定します。
スクリーンショット 2020-11-20 17.13.17.png

番号 補足
x-www-form-urlencoded
KEY に url
VALUE に Webhook URL https://your_domain.com/webhook/twitter ではなく、自分の Webhook URL を設定すること

終わりに

結構罠があって大変でしたがなんとか Webhook URL を登録することができたと思います。エラーコードで調べてもあまり大した情報がないということと、Twitter のトラブルシューティングやドキュメントページが丁寧なようでいまいちよくわからない内容だったということがあって原因を解決するのに時間がかかりました。

特に罠だと思ったのが、公式ドキュメント にはクエリパラメータとして Webhook URL を指定する例が載っているのにこれではうまくいかないという点ですね。

それから、Twitter のアプリを登録するページの UI や URL が昔とだいぶ変わっていて、現在の UI で紹介されている記事がほとんど見つからなかったのも地味に戸惑ったポイントでした。

この記事が参考になりましたら幸いです。

参考サイト


  1. 無料版は Free Premium という名前らしいですが、無料なのにプレミアムってなんか不思議なネーミングですね。 

  2. 2020 年 11 月 20 日現在 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Box UI Elementsを自前でホスティングする方法

Box UI Elementsを自前でホスティングする方法

BOX UI Elements は、React.jsを使っていない場合、CDNからJSファイルとCSSファイルをダウンロードして利用します。
これらのリソースをCDNを使わずに自前でホスティングする方法をメモしておきます。

まとめ (TL;DR)

1. box-ui-elements をCloneして、CSSがフォントを直接参照してる部分を書き換える。

変更するファイルはこれ。
https://github.com/box/box-ui-elements/blob/v12.0.0/src/elements/common/fonts.scss
ビルドする前に、https://cdn01.boxcdn.netとなってる4箇所を、http://localhost:3000 などに書き換えておきます。
マシなやり方あればおしえてください。

2. box-ui-elemensをビルドする。
全ロケール、React.js有り無しパターン生成
yarn release:cdn

または、

ja-JPとReact入りのみ
yarn setup; LANGUAGE=ja-JP REACT=true yarn build:prod:dist
3. box-content-preview をビルドする
yarn install && yarn build:i18n && yarn build:prod
4. Font、box-ui-elements、box-content-preview をホストする

1でダウンロードしておいたFontと、3、4で生成したものをホストします

5. box-ui-elementsの利用時に、optionsに、staticHostpreviewLibraryVersionを指定する
  • staticHostは自前のホストサーバー
  • previewLibraryVersionはBUIEが指している単体のPreviewとバージョンが違うときだけ指定
  contentExplorer.show(folderId, token, {
      container: ".container",           
      staticHost: "http://localhost:3000",
      previewLibraryVersion: "2.58.0"    
  });

Box UI Elementsの構成

前提知識として、Box UI Elementsの注意点を書いておきます。
BOX UI Elements(以降BUIEと表記)に関する詳細は、以下のガイドをまずは参照してください。

BOX DevのUI Elementsガイド
https://ja.developer.box.com/guides/embed/ui-elements/

BUIEはPreviewの中身が別プロジェクト

BUIEは、ガイドにあるように、6個のエレメントでできています。
このうち、BUIEのContent Previewは、Preview機能を単体で提供する、box-content-previewのラッパーです。

Github: box-ui-elements
https://github.com/box/box-ui-elements

Github: box-content-preview
https://github.com/box/box-content-preview

BUIEガイドのインストールの箇所で、CDN版のURLが、Content PreviewだけURLのフォーマットとバージョンが違うのは、
実はbox-ui-elementsのContent Previewではなく、box-content-previewのPreviewを向いています。
なぜガイドがこのようになっているのかは不明ですが、BUIEのContent Previewで問題なく動作します。

BUIEのPreviewじゃないとサイドバーがでない

このPreviewの2つの大きな違いは、BUIEの方だとサイドバーが出せるということです。
box-content-previewのPreviewだとサイドバーを出せません。

ガイドには書かれていませんが、CDNからインストールするときのURLも、BUIEのPreviewを使いたいときは、その他のElementと同じ形で以下のように指定して取得可能です。
https://cdn01.boxcdn.net/platform/elements/11.0.2/en-US/preview.js

ガイドに書いてある以下のURLは、単体のPreviewのインストールURLとなります。
https://cdn01.boxcdn.net/platform/preview/2.34.0/en-US/preview.js

また、グローバル変数の下に作られるオブジェクト名も以下のように変わります。

BUIE Preview: Box.ContentPreview
単体 Preview: Box.Preview

両者の使い方はほとんど同じですが、受け取るパラメータに少し違いがあります。
具体的な使用方法は、ガイドのBUIE Sidebarのページの、Sidebar with Content Preview のCodePenのコードを読んでもらうとわかりやすいです。
https://developer.box.com/guides/embed/ui-elements/sidebar/#sidebar-with-content-preview

このサンプルを乗せている以上、BUIE ContentPreviewは使って問題無いはずなのに、手動インストールのURLには乗せていないのでガイドが少しバグってます。

単体のPreviewがBUIEのPreviewからどのように参照されているか

BoxのCDN(https://cdn01.boxcdn.net/) には、BUIEと単体Previewとその他いくつかのものがホストされています。
おそらく以下のような構成です。

https://cdn01.boxcdn.net/
├── fonts
│   └── (1.0.2 のようなバージョン番号)
│       └── lato
└── platform
    ├── elements
    │   └── (11.0.2 のようなバージョン番号)
    │       ├── (ja-JP のようなロケール名)
    │       └── ...
    └── preview
        ├── (2.58.0 のようなバージョン番号)
        │   ├── (ja-JP のようなロケール名)
        │   └── ...
        └── third-party
            ├── doc
            ├── media
            ├── model3d
            ├── swf
            └── text

CDN経由でインストールされたBUIEは、/platform/elements/11.0.2/ja-JP/xxx を読み込みます。
BUIE Content Previewは、コードの中から強制的にscriptタグを作成し、/platform/preview/2.58.0/ja-JP/preview.js の読み込みを行います。
これは、React.jsを利用している際にNPM経由でインストールしても、この方法でpreview.jsを読み込んでいます。
なぜこのようにしているかは不明ですが、おそらく、preview以下に依存するファイルが大量にあり、相対パスで一括で取り込んでしまいたいという意図があるような気がします。

これをおこなっているのが、以下の箇所になります。

BUIE Preivewが単体のPreviewを呼び出すためにスクリプトタグを埋め込む箇所
https://github.com/box/box-ui-elements/blob/1803655c777493c34ccc32ae339445f88cdb1e20/src/elements/content-preview/ContentPreview.js#L466

単体のPreviewが、グローバル変数にPreviewオブジェクトを露出させる箇所
https://github.com/box/box-content-preview/blob/83d687ec9ea7f9ff17380c0590e72a947df9ac73/src/lib/Preview.js#L1944

BUIE Preivewが、グローバルの単体Previewを読み込む箇所
https://github.com/box/box-ui-elements/blob/1803655c777493c34ccc32ae339445f88cdb1e20/src/elements/content-preview/ContentPreview.js#L787

Fontの指定が絶対URLになっている

自前でホスティングしようとした場合、BUIEと単体 Preview以外にも、CDNを直接参照しているものがあります。
それが、BUIEのCSSのFontの指定です。

自前でホスティングするためにやらないといけないこと

ここまでをまとめると、BUIEをセルフホスティングしようとしたら、以下のことを行わなければならないということです。

  • フォントを絶対URLで指定している箇所を変更する
  • BUIEをビルドして、生成されたファイルをホストする
  • 単体のPreviewをビルドして、生成されたファイルをホストする
  • BUIEのPreviewがコードから単体のPreviewを読み込むので、これを自前のホストに振り向ける

セルフ・ホスティングを行う

さて、本題です。
ここからホスティングを行う準備をしていきます。

フォントを絶対URLで指定している箇所を変更する

https://github.com/box/box-ui-elements からCloneします。

以下のファイルを開き、ホストの部分を書き換えます。
https://github.com/box/box-ui-elements/blob/v12.0.0/src/elements/common/fonts.scss

fonts.scss
@font-face {
    font-weight: normal;
    font-family: 'Lato';
    font-style: normal;
    src: local('Lato Regular'), local('Lato-Regular'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Regular.woff2') format('woff2'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Regular.woff') format('woff');
}

@font-face {
    font-weight: bold;
    font-family: 'Lato';
    font-style: normal;
    src: local('Lato Bold'), local('Lato-Bold'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Bold.woff2') format('woff2'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Bold.woff') format('woff');
}

ここでは、https://cdn01.boxcdn.netとなっている4箇所を、http://localhost:3000 などに書き換えておきます。
運用環境に合わせて変更してください。
イケてないですね・・ ほかにいいやり方あれば教えてください。
利用するときにCSSで上書きできる気もするのですが・・
( @font-faceで名前を変えて定義し、font-familyを!importatで上書きしてみましたがうまくいきませんでした・・・ )
CDNのフォントはホストできるようにダウンロードしておいてください。

BUIEをビルドして、生成されたファイルをホストする

BUIEのCDN版のビルド方法は、ガイドに説明はのっていませんが以下のコマンドで行えます。

yarn release:cdn

このコマンドは、package.jsonを見てもらうとわかりますが、/scrips/prod.jsを実行します。
準備されているロケールに対して、Reactが入ってるものと入っていないものをそれぞれ生成します。
この実行は非常に時間がかかり、私の環境では2時間近くかかりました。
もしも日本語用でReactを含んだものだけを生成したい場合、以下のコマンドでクイックに生成可能です。

yarn setup; LANGUAGE=ja-JP REACT=true yarn build:prod:dist

このコマンドを実行すると、/distフォルダ以下に以下がつくられます。
0.0.0-semantically-released というのは、package.jsonのversionの値です。
おそらくCIで、12.0.0のように適切なバージョンに置き換えて生成してるものと思います。

.
└── 0.0.0-semantically-released
    └── ja-JP
        ├── explorer.css
        ├── explorer.js
        ├── openwith.css
        ├── openwith.js
        ├── picker.css
        ├── picker.js
        ├── preview.css
        ├── preview.js
        ├── sharing.css
        ├── sharing.js
        ├── sidebar.css
        ├── sidebar.js
        ├── uploader.css
        └── uploader.js

単体のPreviewをビルドして、生成されたファイルをホストする

次に、単体のPreviewをビルドします。
Content PreviewのSelf Hostingパッケージの作り方はこちらに説明があります。(ちょっと間違ってます・・・汗)

正しくは以下です。

yarn install && yarn build:i18n && yarn build:prod

このコマンドを実行すると、/distフォルダに以下が作られます
バージョン番号 2.58.0の下にロケール別のフォルダや、third-partyというフォルダが作られます。

.
├── 2.58.0
│   ├── bn-IN
│   ├── (... 省略:サポートされているロケール毎のフォルダ)
│   └── zh-TW
└── third-party
    ├── doc
    │   ├── 1.17.0
    │   ├── ( ... 省略 )

    ├── media
    │   ├── 0.127.0
    │   ├── (... 省略)
    ├── model3d
    │   ├── 1.10.1
    │   │   └── WebVR
    │   │       ├── (... 省略)
    │   ├── (...省略)
    ├── swf
    │   └── 0.112.0
    └── text
        ├── 0.112.0
        └── 0.114.0

あとで解説しますが、ここで生成した2.58.0のようなバージョンは、フォルダ名に反映されますが、このフォルダ名はBUIEのPreviewが指定してきます。
BUIE Previewと単体Previewを連動させるため、バージョンをあわせる必要があります。
BUIE Previewが指定しているバージョンの単体Previewを元に生成するか、指定の単体Previewのバージョンをパラメータで変更します。

サンプルコードを作って動作確認

Express.jsで動作する簡単なサンプルをつくってみます。

雛形を作ります。

mkdir sample
cd sample
npm init -y
npm i express
touch app.js
mkdir lib

以下がフォルダ構成です。
lib フォルダ(名前は何でも・・)以下に、生成されたファイルを置いてください。

.
├── app.js
├── lib
│   ├── fonts
│   │   └── 1.0.2
│   │       └── lato
│   │           ├── Lato-Bold.woff
│   │           ├── Lato-Bold.woff2
│   │           ├── Lato-Regular.woff
│   │           └── Lato-Regular.woff2
│   └── platform
│       ├── elements
│       │   └── 12.0.0
│       │       └── ja-JP
│       └── preview
│           ├── 2.58.0
│           │   ├── bn-IN
│           │   ├── ...
│           └── third-party
│               ├── doc
│               ├── media
│               ├── model3d
│               ├── swf
│               └── text
└── package.json

app.js はこんな感じです。

app.js
const path = require("path");
const express = require("express");
const app = express();

const HOST = "http://localhost:3000";
const ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //開発者トークンを利用

const oneHour = 1000 * 60 * 60;
app.use(
  "/platform",
  express.static(path.join(__dirname, "lib", "platform"), { maxAge: oneHour })
);
app.use(
  "/fonts",
  express.static(path.join(__dirname, "lib", "fonts"), { maxAge: oneHour })
);

app.get("/explorer", async (req, res) => {
  res.set("Content-Type", "text/html");
  res.send(
    `
    <!DOCTYPE html>
    <html lang="en-US">
    <head>
        <meta charset="utf-8"/>
        <title>BUIE Self Hosting Sample</title>
        <script src="${HOST}/platform/elements/12.0.0/ja-JP/explorer.js"></script>
        <link rel="stylesheet" href="${HOST}/platform/elements/12.0.0/ja-JP/explorer.css"/>
    </head>
    <body>
    <div class="container" style="height:600px"></div>

    <script>
        const folderId = "0";
        const token = "${ACCESS_TOKEN}";
        const contentExplorer = new Box.ContentExplorer();
        contentExplorer.show(folderId, token, {
            container: ".container",           
            staticHost: "${HOST}",
            previewLibraryVersion: "2.58.0"    
        });
    </script>
    </body>
    </html>
    `
  );
});

app.get("/preview", async (req, res) => {
  res.set("Content-Type", "text/html");
  res.send(
    `
    <!DOCTYPE html>
    <html lang="en-US">
    <head>
        <meta charset="utf-8"/>
        <title>BUIE Self Hosting Sample</title>
        <script src="${HOST}/platform/elements/12.0.0/ja-JP/preview.js"></script>
        <link rel="stylesheet" href="${HOST}/platform/elements/12.0.0/ja-JP/preview.css"/>
    </head>
    <body>
    <div class="container" style="height:600px"></div>

    <script>
        const fileId = "727216965561";
        const token = "${ACCESS_TOKEN}";
        const ContentPreview = new Box.ContentPreview();
        ContentPreview.show(fileId, token, {
            container: ".container", 
            staticHost: "${HOST}",
            previewLibraryVersion: "2.58.0"          
        });
    </script>
    </body>
    </html>
    `
  );
});

const PORT = process.env.PORT || "3000";
app.listen(PORT, () => {
  console.log("Express Server started on port: " + PORT);
});

BUIEのPreview、Explorerがコードから単体のPreviewを読み込むので、これを自前のホストに振り向ける

BUIEのShowメソッドにわたすオプションで、
staticHostpreviewLibraryVersion を指定しています。
これにより、BUIE Content Previewや、BUIE Content Explorerのように、コードから単体のPreviewを読み込む箇所での、CDNのURLを変えることが可能です。

動作確認

このコードはnode app.jsで実行すると、
以下のURLでBUIEの動作確認が可能です。

http://localhost:3000/explorer,
http://localhost:3000/preivew

ブラウザにChromeをお使いであれば、検証 → Networkから、ダウンロードされるリソースがすべてCDNでなくローカルから落ちてきていることが確認可能です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINEの絵文字・スタンプメッセージ送信メモ

これはうまくいくけど、

                let text_length = pushText.length;
                pushText += "$"

// チャンネルに登録されている方たちに連絡
                client.broadcast([{
                    type: "text",
                    text: pushText,
                    "emojis": [
                        {
                            "index": text_length,
                            "productId": "5ac1bfd5040ab15980c9b435",
                            "emojiId": "002"
                        }
                    ]
                }]).then(data => console.log(data))

こっちのスタンプはうまくいかんのなんでやろ。指定の仕方がまちがってるのか?

                client.broadcast([{
                    type: "sticker",
                    packageId: "11537",
                    stickerId: "520027451"
                }]).then(data => console.log(data))
                .catch(e => console.log(e))

追記⇒ただのIDのコピペミス!!「520027451」の最後の1がいらなかった。見たところ、他のも全部8桁や。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タスクランナーで作ったサイトをHerokuでデプロイする

npm-scriptsやgulpで静的サイトを作った際にHerokuをテストサーバにしたい時の手順です。

前提

npm-scriptsやgulpで静的サイトを作った場合、管理の都合で、静的サイトはgitigoreしていることが多いと思います。
同じリポジトリのまま、Herokuへデプロイする手順です。

手順

(1) Heroku上でnodeでサーバを立ち上げるファイルを作る

# Procfileを作る
echo 'web: node server' >> Procfile

# expressをインストール
npm i express

# server.jsを作成する
touch server.js

(2) Herokuでサーバーを立ち上げるserver.jsを編集

server.js
var express = require('express');
var app = express();

var user = process.env.USER;
var pass = process.env.PASS;

app.set('port', process.env.PORT || 3000);

if (user && pass) {
  app.use(express.basicAuth(user, pass));
}

app.use(express.logger('dev'));
app.use(express.compress());
app.use(express.static(__dirname + '/dist'));

app.listen(app.get('port'), function() {
  console.log('Server listening on port %s', app.get('port'));
});

/dist をルートディレクリとしてサイトを作成している想定です。必要に応じて編集してください。

(3) package.jsonへheroku環境でサイトをビルドするスクリプトを入力

package.json
{
  "scripts": {
    "postinstall": "gulp build" 
  }
}

Heroku上でpackageのインストールが完了したあとにpostinstallが実行されます。
postinstallにはサイトをビルドするスクリプトを記入してください。

(4) デプロイする

# アプリーケーション
heroku create

# デプロイ
git push heroku master

# アプリケーションを開く
heroku open

heroku create アプリ名でアプリ名を指定することもできます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む