定期的にScrapboxのbackupをdownloadするScript
使い方
deployする必要があるのかはよくわからない……
実装
前回実行した時刻と、backup fileの生成時刻とを照らし合わせて、新しくできたbackupをdownloadする
OneDriveなど、他のcloud storageでも使えるようにすると便利かも

2021-01-31 23:26:34 とりあえず書きました

scrapboxでベタ打ちしただけで、テストもなんにもしていません
誰かテストしてくれ
2021-02-01 05:56:40 テスト完了!

実装したいこと
backupの最大数を制限する
現状だと、容量のある限りbackup filesが増えてしまう
最大数に到達したら、古いbackup fileから消すようにしたい
同じ名前のbackup fileがあったら上書きする
設定をjson fileから行う
backupするprojectやbackupの最大数など
メイン関数
この関数をタイマーで定期的に実行する
PROJECTS
: backupを取るprojectのリストをJSONに変換した文字列
LAST_BACKUPED_LIST
: 各projectから最後に取得したbackup fileの作成日時のリスト
なければ勝手に作られる
設定しやすいように、helper関数を用意しておきました

helper.gs(js)function initScriptProperties() {
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('PROJECTS', JSON.stringify(['your-project-name',]));
scriptProperties.setProperty('CONNECT_SID', 'xxx');
}
LAST_BACKUPED_LIST
を消すやつ
helper.gs(js)function clearLastBackupTime(){
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.deleteProperty('LAST_BACKUPED_LIST');
}
main.gs(js)function main() {
const scriptProperties = PropertiesService.getScriptProperties();
const projects = JSON.parse(scriptProperties.getProperty('PROJECTS')); // 複数のprojectを指定可能
const connect_sid = scriptProperties.getProperty('CONNECT_SID');
let lastbackupedList = JSON.parse(scriptProperties.getProperty('LAST_BACKUPED_LIST') || '[]');
const folder = DriveApp.getFolderById('xxx'); // お好みのfolderを選択してください
lastbackupedList = projects.map((project, i) => downloadBackup({ project, connect_sid, folder, lastbackuped: lastbackupedList[i] || 0 }));
scriptProperties.setProperty('LAST_BACKUPED_LIST', JSON.stringify(lastbackupedList));
}
V8
engineを使っているのになんで
??
が使えないんだよ

指定のfolderに新しいbackup filesを保存する
cookie_sid
がバケツリレーになっているのをなんとかできないかな

直近1ファイルで十分な気がする

保存するbackup fileの数を指定できるようにすればいいか

main.gs(js)const zero = n => String(n).padStart(2, '0');
function downloadBackup({ project, connect_sid, folder, lastbackuped }) {
const backups = getBackupList({ project, connect_sid });
const backupIds = backups
.flatMap(({ backuped, id }) => backuped > lastbackuped ? [id] : [])
.slice(0, 10); // 直近10ファイルまで取得する
if (backupIds.length === 0) {
console.log('no backup files found.');
return lastbackuped;
}
const jsons = getBackupFiles({ project, connect_sid, fileIds: backupIds });
console.log('Save backup files...');
let saveNum = 0;
jsons.forEach(json => {
const exported = new Date(json.exported * 1000);
const fileName = `${project}_${exported.getFullYear()}${zero(exported.getMonth() + 1)}${zero(exported.getDate())}${zero(exported.getHours())}${zero(exported.getMinutes())}${zero(exported.getSeconds())}.json`;
日付の文字列を作るところは、関数に切り出したほうが見やすいかも

main.gs(js) folder.createFile(fileName, JSON.stringify(json, null, 2), 'application/json');
MIME typeの指定はなくても動くみたい
main.gs(js) saveNum++;
console.log(`Saved: ${saveNum}/${jsons.length}`);
});
// backupの最終更新日時を返す
const newLastBackuped = Math.max(...jsons.map(({ exported }) => parseInt(exported)));
console.log(`Finish saving. Last backuped date: ${new Date(newLastBackuped * 1000)}`);
読みやすいように、 YYYY-MM-DD hh:mm:ss
の形式で最終更新日時を表示したい
指定したprojectのbackup fileのlistを取得する
main.gs(js)function getBackupList({ project, connect_sid }) {
console.log(`Start fetching the backup list of /${project}...`);
const response = UrlFetchApp
.fetch(`https://scrapbox.io/api/project-backup/${project}/list`, {
headers: { Cookie: `connect.sid=${connect_sid}` },
});
const json = JSON.parse(response.getContentText());
console.log(`Finish fetching.`, { backupNum: json.backups.length });
return json.backups;
}
指定したbackup fileをdownloadする
main.gs(js)function getBackupFiles({ project, fileIds, connect_sid }) {
console.log(`Start fetching ${fileIds.length} backups from /${project}...`, fileIds);
const responses = UrlFetchApp
.fetchAll(fileIds.map(fileId => {
return {
url: `https://scrapbox.io/api/project-backup/${project}/${fileId}.json`,
headers: { Cookie: `connect.sid=${connect_sid}` },
};
})
);
async
\ await
が使えないので結構不便
main.gs(js) const jsons = responses.map(response => JSON.parse(response.getContentText()));
console.log('Finish fetching.');
return jsons;
}
appsscript.json{
"timeZone": "Asia/Tokyo",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}

さんに教えてもらった
