Skip to content

Instantly share code, notes, and snippets.

@17number
Last active May 2, 2018 05:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 17number/aba0e6f64fd1d4bd73cb91b390f31c42 to your computer and use it in GitHub Desktop.
Save 17number/aba0e6f64fd1d4bd73cb91b390f31c42 to your computer and use it in GitHub Desktop.
はてなブログの過去記事を定期的にGASでツイート
/* ====== 各種変数 ====== */
// Twitter APIキー・シークレット
var CONSUMER_KEY = 'YourConsumerKey';
var CONSUMER_SECRET = 'YourConsumerSecret';
var twitter = TwitterWebService.getInstance(
CONSUMER_KEY,
CONSUMER_SECRET
);
// ブログ情報
var BLOG_URL = 'YourBlogURL';
// 過去記事Botの宣伝に協力OK?
var PROMOTE_OK = true;
// 記事一覧を書き出すシート
var TARGET_SHEET = "シート1";
// ツイート対象から除外するシート
var EXCLUDE_SHEET = "シート2";
// 投稿時刻を正確に時間指定したい人向け(時分を入力、13:05 → "1305")
// 注意事項:
// ・setTrigger の前に deleteTrigger を必ず実行すること
// ・setTrigger の動作時刻より、後の時刻を設定すること
var POST_TIMES = [
"2100",
"2105",
"2110",
"2115",
"2120",
"2125",
"2130",
];
/* ====== Twitter 関連 ====== */
// 認証
function authorize() {
twitter.authorize();
}
// 認証解除
function reset() {
twitter.reset();
}
// 認証後のコールバック
function authCallback(request) {
return twitter.authCallback(request);
}
// ツイートを投稿
function postUpdateStatus(tweetString, tweetID) {
var service = twitter.getService();
var tweetID = (tweetID !== undefined) ? tweetID : null;
var response = service.fetch('https://api.twitter.com/1.1/statuses/update.json', {
method: 'post',
payload: {
status: tweetString,
in_reply_to_status_id: tweetID
}
});
return JSON.parse(response);
}
//2バイト文字は2として文字数をカウント
function strLenJ(str) {
var len = 0;
str = escape(str);
for (var i = 0; i < str.length; i++, len++) {
if (str.charAt(i) == "%") {
if (str.charAt(++i) == "u") {
i += 3;
len++;
}
i++;
}
}
return len;
}
// 文字列 切り出し
function substr(text, len, truncation) {
if (truncation === undefined) { truncation = ''; }
var text_array = text.split('');
var count = 0;
var str = '';
for (i = 0; i < text_array.length; i++) {
var n = escape(text_array[i]);
if (n.length < 4) count++;
else count += 2;
if (count > len) {
return str + truncation;
}
str += text.charAt(i);
}
return text;
}
/* ====== 過去記事抽出など ====== */
// 過去記事の投稿
function postOldEntry() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(TARGET_SHEET);
var lastRow = sheet.getLastRow();
// スプレッドシートの更新とタイミングが重なった場合は何も投稿しない
if(lastRow == 0) return;
// スプレッドシートからデータ取得
var publishDates = sheet.getRange("A1").offset(0, 0, lastRow).getValues();
var updateDates = sheet.getRange("B1").offset(0, 0, lastRow).getValues();
var titles = sheet.getRange("C1").offset(0, 0, lastRow).getValues();
var urls = sheet.getRange("D1").offset(0, 0, lastRow).getValues();
// ランダムに情報抽出
var is_exclude = false;
while(is_exclude == false) {
var rand = Math.ceil(Math.random() * lastRow - 1);
var url = urls[rand][0];
var ex_row = findRow(ss.getSheetByName(EXCLUDE_SHEET), url, 1);
if(ex_row === 0) {
is_exclude = true;
}
}
var publishedStr = publishDates[rand][0];
var updatedStr = updateDates[rand][0];
var title = titles[rand][0];
// 日時フォーマット変更
var published = Utilities.formatDate(new Date(publishedStr), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm');
var updated = Utilities.formatDate(new Date(updatedStr), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm');
var tweetStr = "";
tweetStr += "🤖<カコキジ!! ";
tweetStr += "#過去記事bot #はてなブログ \n";
tweetStr += url + "\n";
tweetStr += "🕘" + published + " 投稿\n";
tweetStr += "🔃" + updated + " 更新\n";
tweetStr += "📰" + title + "\n";
// 文字数チェック(url は 23文字固定でカウント)
var tweetLength = strLenJ(tweetStr) - strLenJ(url) + 23;
if(tweetLength > 280) {
tweetStr = substr(tweetStr, 276 - 23 + strLenJ(url), "...");
}
// 過去記事 投稿
response = postUpdateStatus(tweetStr);
// 過去記事bot の作り方記事にリンクを貼る
if(PROMOTE_OK) {
var tweetID = response.id_str;
tweetStr = "#はてなブログ 向け #過去記事bot の導入方法はこちら\nhttps://twitter.com/stray_engineer/status/975298853061607424";
response = postUpdateStatus(tweetStr, tweetID);
}
}
// スプレッドシート クリア
function clearSheet() {
var myActiveSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var myActiveSheet = myActiveSpreadSheet.getSheetByName(TARGET_SHEET);
myActiveSheet.clear();
}
// スプレッドシートに記事一覧情報 入力
function scraipingHatenaBlog() {
var myActiveSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var myActiveSheet = myActiveSpreadSheet.getSheetByName(TARGET_SHEET);
// 末尾が"/"の場合 削除
if(BLOG_URL[BLOG_URL.length - 1] === "/") { BLOG_URL = BLOG_URL.slice(0, BLOG_URL.length - 1); }
// RSS 取得
var nonce = getNonce("");
var response = UrlFetchApp.fetch(BLOG_URL + "/feed?page=" + nonce);
// エントリー情報 抽出
var myRegexp = /<entry>([\s\S]*?)<\/updated>/gi;
var match = response.getContentText().match(myRegexp);
// 過去記事を全て処理
while(match != null) {
for(var i in match) {
// 投稿日, 更新日, タイトル, URL を入力
var matchData = match[i];
writeData(myActiveSheet, matchData);
// 2ページ目以降を処理するために nonce 更新
var published = fetchString(matchData, "<published>", "<\/published>");
nonce = getNonce(published);
}
// 2ページ目以降を取得
response = UrlFetchApp.fetch(BLOG_URL + "/feed?page=" + nonce);
match = response.getContentText().match(myRegexp);
}
}
// Nonce 取得
function getNonce(dateString) {
var date = new Date();
if(dateString != "") {
date = new Date(dateString);
}
return Math.floor((date.getTime()/1000)).toString();
}
// 文字列抽出
function fetchString(str, pre, suf) {
var reg = new RegExp(pre + '.*?' + suf);
var data = str.match(reg)[0]
.replace(pre, '')
.replace(suf, '');
return data;
}
// Spreadsheet 書き込み
function writeData(sheet, matchData) {
var published = fetchString(matchData, "<published>", "<\/published>");
var updated = fetchString(matchData, "<updated>", "<\/updated>");
var title = fetchString(matchData, "<title>", "<\/title>");
var link = fetchString(matchData, "<link href=\"", "\"\/>");
// https化されている場合、?utm_source=feed が付くので除去しておく
if(link.lastIndexOf('?') > 0) {
link = link.substring(0, link.lastIndexOf('?'));
}
var row = sheet.getLastRow() + 1
sheet.getRange(row, 1).setValue(published);
sheet.getRange(row, 2).setValue(updated);
sheet.getRange(row, 3).setValue(title);
sheet.getRange(row, 4).setValue(link);
}
// シート内検索
function findRow(sheet, val, col){
if(sheet == null) return 0;
var dat = sheet.getDataRange().getValues();
for(var i=1; i<dat.length; i++){
if(dat[i][col-1] === val){
return i+1;
}
}
return 0;
}
// --- 正確に時間指定したい人向け ---
// トリガー設定
function setTrigger() {
var len = POST_TIMES.length;
for(var i=0; i<POST_TIMES.length; i++) {
var triggerDay = new Date();
triggerDay.setHours(POST_TIMES[i].substr(0, 2));
triggerDay.setMinutes(POST_TIMES[i].substr(2, 2));
ScriptApp.newTrigger("postOldEntry").timeBased().at(triggerDay).create();
}
}
// トリガー削除
function deleteTrigger() {
var triggers = ScriptApp.getProjectTriggers();
for(var i=0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() == "postOldEntry") {
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment