/// /// /// import { pin, unpin, patch, useStatusBar, sleep, makeSocket, disconnect, format, } from "./deps.ts"; import { listPinnedPages } from "./list.ts"; import type { Scrapbox, Socket } from "./deps.ts"; declare const scrapbox: Scrapbox; export interface DiaryInit { /** 与えられた日付の日記ページのテンプレートを作る */ makeDiary: (date: Date) => { title: string; header: string[]; footer: string[]; }, /** 今日以外の日記ページかどうかを判断する函数 * * @param title 判断対象のページタイトル * @param today 今日の日付 * @param 今日以外の日記ページなら`true`, それ以外のページは `false` */ isOldDiary: (title: string, today: Date) => boolean; } // initialize export const launch = ( project: string, init: DiaryInit & { interval?: number }, ) => { const interval = init.interval ?? 24 * 3600 * 1000; const handleChange = () => scrapbox.Project.name === project ? startObserve(project, interval, init) : endObserve(); handleChange(); scrapbox.addListener("project:changed", handleChange); }; let updateTimer: number | undefined; const startObserve = async ( project: string, interval: number, init: DiaryInit, ) => { endObserve(); await pinDiary(project, new Date(), init); updateTimer = setInterval( () => pinDiary(project, new Date(), init), interval, ); }; const endObserve = () => clearInterval(updateTimer); export const pinDiary = async ( project: string, date: Date, { makeDiary, isOldDiary, }: DiaryInit, ): Promise => { const { render, dispose } = useStatusBar(); let socket: Socket | undefined; try { // 今日以外の日付ページを外す render( { type: "spinner" }, { type: "text", text: `unpin other diary pages...`}, ); socket = await makeSocket(); for await (const { title } of listPinnedPages(project)) { if (!isOldDiary(title, date)) continue; await unpin(project, title, { socket }); } // 今日の日付ページをピン留めする const { title, header, footer } = makeDiary(date); render( { type: "spinner" }, { type: "text", text: `pin "/${project}/${title}"...`}, ); await pin(project, title, { socket, create: true }); // 今日の日付ページにtemplateを挿入する render( { type: "spinner" }, { type: "text", text: `format "/${project}/${title}"...`}, ); await patch(project, title, (lines) => [ lines[0].text, ...format( lines.slice(1).map(line => line.text), header, footer, ), ], { socket }); render( { type: "check-circle" }, { type: "text", text: `Pinned "/${project}/${title}".`}, ); } catch(e: unknown) { render( { type: "exclamation-triangle" }, { type: "text", text: e instanceof Error ? `${e.name} ${e.message}` : `Unknown error! (see developper console)`, }, ); console.error(e); } finally { if (socket) await disconnect(socket); await sleep(1000); dispose(); } };