|
| 1 | +import { config } from "https://deno.land/x/[email protected]/mod.ts"; |
| 2 | + |
| 3 | +interface Page { |
| 4 | + title: string; |
| 5 | + lines: string[]; |
| 6 | + id?: string; |
| 7 | + created?: number; |
| 8 | + updated?: number; |
| 9 | +} |
| 10 | +interface ExportResponse { |
| 11 | + name: string; |
| 12 | + displayName: string; |
| 13 | + exported: number; |
| 14 | + pages: Page[]; |
| 15 | +} |
| 16 | + |
| 17 | +const cookie = (sid: string) => `connect.sid=${sid}`; |
| 18 | + |
| 19 | +async function csrfToken(sid: string) { |
| 20 | + const res = await fetch("https://scrapbox.io/api/users/me", { |
| 21 | + headers: { Cookie: cookie(sid) }, |
| 22 | + }); |
| 23 | + const json = await res.json(); |
| 24 | + const { csrfToken } = json as { csrfToken: string }; |
| 25 | + return csrfToken; |
| 26 | +} |
| 27 | + |
| 28 | +async function exportJSON(projectName: string, sid: string) { |
| 29 | + const res = await fetch( |
| 30 | + `https://scrapbox.io/api/page-data/export/${projectName}.json`, |
| 31 | + { |
| 32 | + method: "POST", |
| 33 | + headers: { |
| 34 | + Cookie: cookie(sid), |
| 35 | + "X-CSRF-TOKEN": await csrfToken(sid), |
| 36 | + }, |
| 37 | + }, |
| 38 | + ); |
| 39 | + const { pages } = (await res.json()) as ExportResponse; |
| 40 | + |
| 41 | + return pages; |
| 42 | +} |
| 43 | + |
| 44 | +async function importJSON( |
| 45 | + projectName: string, |
| 46 | + sid: string, |
| 47 | + importPages: Page[], |
| 48 | +) { |
| 49 | + const formData = new FormData(); |
| 50 | + formData.append( |
| 51 | + "import-file", |
| 52 | + new Blob([JSON.stringify({ pages: importPages })], { |
| 53 | + type: "application/octet-stream", |
| 54 | + }), |
| 55 | + ); |
| 56 | + formData.append("name", "undefined"); |
| 57 | + |
| 58 | + return await fetch( |
| 59 | + `https://scrapbox.io/api/page-data/import/${projectName}.json`, |
| 60 | + { |
| 61 | + method: "POST", |
| 62 | + headers: { |
| 63 | + Cookie: cookie(sid), |
| 64 | + Accept: "application/json, text/plain, */*", |
| 65 | + "X-CSRF-TOKEN": await csrfToken(sid), |
| 66 | + }, |
| 67 | + body: formData, |
| 68 | + }, |
| 69 | + ); |
| 70 | +} |
| 71 | + |
| 72 | +const env = config(); |
| 73 | +const sid = env["SID"]; |
| 74 | +const exportingProjectName = env["SOURCE_PROJECT_NAME"]; //インポート元(本来はprivateプロジェクト) |
| 75 | +const importingProjectName = env["DESTINATION_PROJECT_NAME"]; //インポート先(publicプロジェクト) |
| 76 | + |
| 77 | +console.log(`Exporting a json file from "/${exportingProjectName}"...`); |
| 78 | +const pages = await exportJSON(exportingProjectName, sid); |
| 79 | +console.log("exported: ", pages); |
| 80 | +const importPages = pages.filter(({ lines }) => |
| 81 | + lines.some((line) => line.includes("[public.icon]")) |
| 82 | +); |
| 83 | +if (importPages.length > 0) { |
| 84 | + console.log(`Importing the page data to "/${importingProjectName}"...`); |
| 85 | + await importJSON(importingProjectName, sid, importPages); |
| 86 | +} else { |
| 87 | + console.log("No page to be imported found."); |
| 88 | +} |
0 commit comments