定期的にScrapboxのbackupをdownloadするScript
使い方
deployする必要があるのかはよくわからない……
/icons/わからん.iconyosider.icon
実装
前回実行した時刻と、backup fileの生成時刻とを照らし合わせて、新しくできたbackupをdownloadする
OneDriveなど、他のcloud storageでも使えるようにすると便利かもtakker.icon 2021-01-31 23:26:34 とりあえず書きましたtakker.icon
scrapboxでベタ打ちしただけで、テストもなんにもしていません
誰かテストしてくれ
2021-02-01 05:56:40 テスト完了!takker.icon
実装したいこと
backupの最大数を制限する
現状だと、容量のある限りbackup filesが増えてしまう
最大数に到達したら、古いbackup fileから消すようにしたい
同じ名前のbackup fileがあったら上書きする
設定をjson fileから行う
backupするprojectやbackupの最大数など
メイン関数
この関数をタイマーで定期的に実行する
PROJECTS: backupを取るprojectのリストをJSONに変換した文字列
LAST_BACKUPED_LIST: 各projectから最後に取得したbackup fileの作成日時のリスト
なければ勝手に作られる
設定しやすいように、helper関数を用意しておきましたtakker.icon
code:helper.gs(js)
function initScriptProperties() {
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('CONNECT_SID', 'xxx');
}
LAST_BACKUPED_LISTを消すやつ
code:helper.gs(js)
function clearLastBackupTime(){
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.deleteProperty('LAST_BACKUPED_LIST');
}
code: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: lastbackupedListi || 0 })); scriptProperties.setProperty('LAST_BACKUPED_LIST', JSON.stringify(lastbackupedList));
}
V8 engineを使っているのになんで ??が使えないんだよtakker.icon
指定のfolderに新しいbackup filesを保存する
cookie_sidがバケツリレーになっているのをなんとかできないかなtakker.icon
直近1ファイルで十分な気がするyosider.icon
保存するbackup fileの数を指定できるようにすればいいかtakker.icon
code: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;
日付の文字列を作るところは、関数に切り出したほうが見やすいかもtakker.icon
code:main.gs(js)
folder.createFile(fileName, JSON.stringify(json, null, 2), 'application/json');
MIME typeの指定はなくても動くみたい
code: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の形式で最終更新日時を表示したい
code:main.gs(js)
return newLastBackuped;
}
指定したprojectのbackup fileのlistを取得する
code: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する
code: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が使えないので結構不便
code:main.gs(js)
const jsons = responses.map(response => JSON.parse(response.getContentText()));
console.log('Finish fetching.');
return jsons;
}
code:appsscript.json
{
"timeZone": "Asia/Tokyo",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
/yuta0801/yuta0801.iconさんに教えてもらったtakker.icon