【JavaScript】GAS + TwitterAPIで共有アカウントからつぶやく
前置き
知人が小さなコミュニティを運営している。まあ、サークルみたいなものだ。私はたまーに手伝いをしている。一員なんだけど活動は殆ど出来ていないや🤪
その知人が、「コミュニティのTwttierアカウントから各自が更新情報を発信できると運営が楽になるなー」というような発言からタイトルのようなことを思いついた。
概要
TwitterアカウントのIDやパスワードはメンバーには通知しない
必然的にアプリを何か挟まないといけない
メンバーサイトは、ログイン機能が必要なのである程度はクライアント側に情報を持たせても多分OK
GAS(Google Apps Script)でTwitterAPIを叩いて、コミュニティのページからはGASのAPIを叩く
詳細
Javascript「のみ」でTwitterAPIを叩いてみる - 動かざることバグの如し
今から10分ではじめる Google Apps Script(GAS) で Web API公開 - Qiita
殆どこちらのブログを参考にさせてもらった🎉
GAS側
補足するとすれば、参考にしたブログとは詳細がちょっと変わっている点だと思う。 参考にしたブログの環境は、多分ブラウザ(JQuery使ってるし)だし、ライブラリはリンク切れになっている。
- fetch処理はGAS専用のに書き換え
- ライブラリのファイルは、GASに中身をコピペしている(oauth.gsとsha1.gs)
ちなみに、oauth.gsの中身はこちらで、
oauth.js · GitHub
sha1.gsの中身はこちらだ(↑のファイルの中に書いてあるリンク)
http://pajhome.org.uk/crypt/md5/sha1.js
/** * @param request: {{ * parameter: { * text: string, // ツイートする内容 * cbf: string // Callback function name * } * }} */ function doGet(request) { console.log(request); const requestBody = request.parameter; const text = requestBody.text; const callbackFunctionName = requestBody.cbf; const options = { method: "POST", apiURL: "https://api.twitter.com/1.1/statuses/update.json", // ★ ここを変更。TwitterAPIのキーを発行するページを見れば、名称が多少違っても雰囲気でわかるはず consumerKey: "", consumerSecret: "", accessToken: "", tokenSecret: "", body: text }; const tweetResult = postTweets(options); const out = ContentService.createTextOutput(); // セキュリティ的には微妙らしいが、JSONPとして扱う(そのつながりでGETを受け入れるようにする。意味違うんだけどしゃあない) out.setMimeType(ContentService.MimeType.JAVASCRIPT); out.setContent(callbackFunctionName + "(" + JSON.stringify(tweetResult) + ")"); return out; } function postTweets(options) { const accessor = { consumerSecret: options.consumerSecret, tokenSecret: options.tokenSecret }; const message = { method: options.method, action: options.apiURL, parameters: { oauth_consumer_key: options.consumerKey, oauth_version: "1.0", oauth_signature_method: "HMAC-SHA1", oauth_token: options.accessToken, status: options.body } }; OAuth.setTimestampAndNonce(message); OAuth.SignatureMethod.sign(message, accessor); const url = OAuth.addToURL(message.action, message.parameters); const r = UrlFetchApp.fetch(url, { method: "POST", }); let success; let content; try { content = JSON.parse(r.getContentText()); success = r.getResponseCode() === 200; } catch(ex) { console.error(ex); content = {}; success = false; } const twitterResult = success ? { success: true, msg: "ツイートしました", content: { postUrl: "https://twitter.com/" + content.user.screen_name + "/status/" + content.id_str } } : { success: false, msg: "ツイート中にエラーが発生しました。" }; console.log(twitterResult); return twitterResult; }
HTML側
若干不要な情報も入っていはいるが、テキストエリアに文字を入力し、ボタンを押したらAPIが叩かれる単純なものだ。
window.fetch
やXMLHttpRequest
でもjsonpはできるのかもしれないが、それを調べるのも面倒だったのでjqueryを利用している。それ以外はjqueryも使っていないので、おそらく標準だけでブラウザ側はいけるはず。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Use twitter api</title> </head> <body> <main> <div> <textarea id="status" placeholder="ツイートする情報を入力してください" cols="60" rows="4" ></textarea> </div> <div class="btn-container"> <button class="tweet-btn" onclick="tweets();">ツイートする</button> </div> <div class="tweet-result"> </div> </main> </textarea> <div class="as-console"></div> </body> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script> var endpoint = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; function tweets() { var text = document.getElementById("status").value; if (text == null || text.length === 0) { alert("無言ツイートはできません"); return false; } if (text.length > 140) { alert("長い: " + text.length); return false; } $.ajax({ type: 'GET', url: endpoint, dataType: 'jsonp', data: { text: text, cbf: "cbf" } }); } /** * @param res {{ * success: true, * msg: string, * content: { * postUrl: string, * } * } | { * success: false, * msg: string, * }} */ function cbf(res) { if (!res.success) { alert(res.msg); return; } document.getElementById("status").disabled = true; var currentTweetElement = document.createElement("span"); var link = document.createElement("a"); link.href = res.content.postUrl; link.text = res.content.postUrl; link.target = "_blank"; link.rel = "noopener noreferrer"; currentTweetElement.appendChild(document.createTextNode("今つぶやいたツイート")); currentTweetElement.appendChild(link); document.getElementsByClassName("tweet-result")[0].appendChild(currentTweetElement); } </script> </html>
雑感
jsonpを普段使ったことがないため、ここ回りが一番時間かかった気がする。流れでCORSの勉強も少しすることになったため、まあ良かったかな。 今回はTwitterAPIだったけど、別のAPIを叩くのにもGASは使えそう。 メンバーサイトのようにある程度の機密性がない場合は、ある程度のエラーチェックや何かあった時の通知とかGAS削除とかリスク対応は必要だろうけど。。
GASでconstとかアロー演算が使えるようになったのが地味に嬉しい。