Last active
September 23, 2019 00:08
-
-
Save knz21/16d0c2b7e57072ff33d728aa93571428 to your computer and use it in GitHub Desktop.
TANITAの体組成計連携Tweetを元に作成したグラフを投稿
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// HealthPlanet側のTwitterテンプレート '体重:#WHT#kg 体脂肪率:#BFP#% 筋肉量:#MBK#kg 筋肉スコア:#MBS# 内臓脂肪レベル:#VFL# 基礎代謝量:#BAR# 体内年齢:#BDA#歳 推定骨量:#APB#' | |
var SPREADSHEET_ID = '保存先スプレッドシートのID' | |
var COL_INDEX = { | |
'date': 1, | |
'weight': 2, | |
'fat': 3, | |
'muscle': 4, | |
'muscle_score': 5, | |
'visceral_fat': 6, | |
'metabolism': 7, | |
'body_age': 8, | |
'bone': 9 | |
} | |
var COMPOSITION_COLUMN_SIZE = 8 | |
var CHART_ROW_SIZE = 28 | |
var CHART_COLUMN_SIZE = 3 | |
var SHEET = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('シート名') | |
// trigger begin | |
// グラフをtwitterに投稿 (週次とか) | |
function tweetChartImage() { | |
const twitterService = getTwitterService() | |
if (twitterService.hasAccess()) { | |
const params = { | |
'status': 'グラフ #tanita #healthplanet', | |
'media_ids': [ | |
uploadImage(twitterService, createChart(COL_INDEX.weight).getBlob()), | |
uploadImage(twitterService, createChart(COL_INDEX.fat).getBlob()), | |
uploadImage(twitterService, createChart(COL_INDEX.muscle).getBlob()), | |
uploadImage(twitterService, createChart(COL_INDEX.metabolism).getBlob()) | |
] | |
} | |
const sendoption = { | |
'method': 'POST', | |
'payload': Object.keys(params).map(function(key) { | |
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]); | |
}).join('&') | |
} | |
twitterService.fetch('https://api.twitter.com/1.1/statuses/update.json', sendoption) | |
} else { | |
Logger.log(service.getLastError()) | |
} | |
} | |
// 体組成をスプレッドシートへ (毎日くらい) | |
function updateDailyComposition() { | |
var twitterService = getTwitterService(); | |
if (twitterService.hasAccess()) { | |
var url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=TwitterのID&count=20&trim_user=t' // @TwitterのIDの最新20tweetを取得 | |
var response = JSON.parse(twitterService.fetch(url, { method: 'GET' })) | |
var newRows = response | |
.filter(function (tweet) { return isComposition(tweet) && isNew(tweet) }) | |
.map(function (tweet) { return createRow(tweet.created_at, tweet.text) }) | |
if (newRows.length > 0) { | |
SHEET.insertRows(2, newRows.length) | |
SHEET.getRange(2, 1, newRows.length, newRows[0].length).setValues(newRows) | |
calcMovingAverage(newRows.length) | |
} | |
} else { | |
Logger.log(service.getLastError()) | |
} | |
} | |
// trigger end | |
function isComposition(tweet) { | |
return tweet.text.indexOf('#tanita') >= 0 && tweet.text.indexOf('体重:') == 0 | |
} | |
function isNew(tweet) { | |
try { | |
return new Date(tweet.created_at).getTime() > SHEET.getRange(2, 1).getValue().getTime() | |
} catch (e) { | |
return true | |
} | |
} | |
/** | |
* 保存用のrowを作成 | |
* @param createdAt Date 投稿時間 | |
* @param text String tweet本文: '体重:60.00kg 体脂肪率:15.00% ...' | |
* @returns {Array.<*>} [投稿時間, 60.00, 15.00, ...] | |
*/ | |
function createRow(createdAt, text) { | |
return [ new Date(createdAt) ].concat( | |
text | |
.replace(/kg/g, '').replace('%', '').replace('歳', '').split(' ') | |
.filter(function (element) { return element.indexOf(':') > 0 }).map(function (value) { return value.split(':')[1] }) | |
) | |
} | |
function uploadImage(twitterService, image) { | |
var options = { 'method': 'POST', 'payload': {'media_data': Utilities.base64Encode(image.getBytes())} } | |
return JSON.parse(twitterService.fetch('https://upload.twitter.com/1.1/media/upload.json', options))['media_id_string'] | |
} | |
function calcMovingAverage(newRowSize) { | |
for (var i = 0; i < newRowSize; i++) { | |
SHEET.getRange(4 + i, COMPOSITION_COLUMN_SIZE + 2, 1, COMPOSITION_COLUMN_SIZE).setValues([transpose(SHEET.getRange(2 + i, 2, 5, COMPOSITION_COLUMN_SIZE).getValues()).map(function (nums) { return avarage(nums) })]) | |
} | |
} | |
function transpose(array) { | |
return array[0].map(function (c, i) { return array.map(function (r) { return r[i] }) }) | |
} | |
function avarage(nums) { | |
return nums.reduce(function (a, c) { return a + c }) / nums.length | |
} | |
function createChart(targetIndex) { | |
var tmpSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('グラフ描画に使うシート名') | |
copyToTmp(tmpSheet, targetIndex) | |
return SHEET.newChart() | |
.addRange(tmpSheet.getRange(1, 1, CHART_ROW_SIZE, CHART_COLUMN_SIZE)) | |
.setChartType(Charts.ChartType.LINE) | |
.setPosition(2, 2, 0, 0) | |
.setOption('title', SHEET.getRange(1, targetIndex).getValue()) | |
.build(); | |
} | |
function copyToTmp(tmpSheet, targetIndex) { | |
copyColumn(tmpSheet, COL_INDEX.date, 1) | |
copyColumn(tmpSheet, targetIndex, 2) | |
copyColumn(tmpSheet, targetIndex + COMPOSITION_COLUMN_SIZE, 3) | |
} | |
function copyColumn(tmpSheet, targetIndex, destIndex) { | |
tmpSheet.getRange(1, destIndex, CHART_ROW_SIZE, 1).setValues(SHEET.getRange(1, targetIndex, CHART_ROW_SIZE, 1).getValues()) | |
} | |
// twitter begin | |
// Twitter AppのConsumer Api Key | |
var CONSUMER_KEY = PropertiesService.getScriptProperties().getProperty('CONSUMER_KEY'); | |
var CONSUMER_SECRET = PropertiesService.getScriptProperties().getProperty('CONSUMER_SECRET'); | |
// 認証URLを取得しログに出力する | |
function logAuthorizeUri() { | |
var twitterService = getTwitterService(); | |
Logger.log(twitterService.authorize()); | |
} | |
// OAuth認証サービスクラスのインスタンス生成・取得 | |
function getTwitterService() { | |
return OAuth1.createService('Twitter') | |
.setAccessTokenUrl('https://api.twitter.com/oauth/access_token') | |
.setRequestTokenUrl('https://api.twitter.com/oauth/request_token') | |
.setAuthorizationUrl('https://api.twitter.com/oauth/authenticate') | |
.setConsumerKey(CONSUMER_KEY) | |
.setConsumerSecret(CONSUMER_SECRET) | |
// リダイレクト時に実行されるコールバック関数を指定する | |
.setCallbackFunction('authCallback') | |
// アクセストークンを保存するPropertyStoreを指定する | |
.setPropertyStore(PropertiesService.getUserProperties()); | |
} | |
// リダイレクト時に実行されるコールバック関数 | |
function authCallback(request) { | |
var twitterService = getTwitterService(); | |
// ここで認証成功時にアクセストークンがPropertyStoreに保存される | |
var isAuthorized = twitterService.handleCallback(request); | |
if (isAuthorized) { | |
return HtmlService.createHtmlOutput('Success'); | |
} else { | |
return HtmlService.createHtmlOutput('Denied'); | |
} | |
} | |
// twitter end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment