複数のページを削除するUserScript
複数のページを一度に削除したいときに使うUserScript
code:js
await (async () => {
await deletePages([
"a", "b"
].map((title) => ({ project: "takker", title})));
})();
code:mod.ts
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/// <reference lib="dom" />
import {
useStatusBar,
makeSocket,
deletePage,
disconnect,
Socket,
} from "../scrapbox-userscript-std/mod.ts";
import { delay } from "../deno_std%2Fasync/mod.ts";
export interface Page {
project: string;
title: string;
}
export const deletePages = async (pages: Page[]): Promise<void> => {
const { render, dispose } = useStatusBar();
let socket: Socket | undefined;
try {
socket = await makeSocket();
let counter = 0;
for (const page of pages) {
await deletePage(page.project, page.title, { socket });
counter++;
render(
{ type: "spinner" },
{ type: "text", text: delete ${counter}/${pages.length} pages...},
);
}
render(
{ type: "check-circle" },
{ type: "text", text: deleted ${pages.length} pages.},
);
} 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 delay(1000);
dispose();
}
}
code:mod.js
var d=e=>{let{fetch:t=globalThis.fetch,hostName:r="scrapbox.io",...o}=e;return{fetch:t,hostName:r,...o}};var ue=e=>typeof e=="object"&&e!==null,me=e=>ue(e)?(e.name===void 0||typeof e.name=="string")&&typeof e.message=="string":!1,B=e=>{try{let t=typeof e=="string"?JSON.parse(e):e;return me(t)?t:!1}catch(t){if(t instanceof SyntaxError)return!1;throw t}};var w=class extends Error{constructor(t){super(${t.status} ${t.statusText} when fetching ${t.url});this.response=t;this.name="UnexpectedResponseError";Error.captureStackTrace&&Error.captureStackTrace(this,w)}},g=async e=>{let t=e.clone(),r=await t.text(),o=B(r);if(!o)throw new w(t);return{ok:!1,value:o}};var j=async e=>{let{sid:t,hostName:r,fetch:o}=d(e??{}),n=new Request(https://${r}/api/users/me,t?{headers:{Cookie:f(t)}}:void 0),s=await o(n);if(!s.ok)throw new w(s);return await s.json()};var f=e=>connect.sid=${e};var D=e=>...e.map((t,r)=>t===" "?"_":!le.includes(t)||r===e.length-1&&fe.includes(t)?encodeURIComponent(t):t).join(""),le='@$&+=:;",',fe=':;",';var A=(e,t,r)=>{let{sid:o,hostName:n,followRename:s,projects:i}=d(r??{}),c=new URLSearchParams;c.append("followRename",${s??!0});for(let p of i??[])c.append("projects",p);let a=https://${n}/api/pages/${e}/${D(t)}?${c.toString()};return new Request(a,o?{headers:{Cookie:f(o)}}:void 0)},F=async e=>{if(!e.ok)return e.status===414?{ok:!1,value:{name:"TooLongURIError",message:"project ids may be too much."}}:g(e);let t=await e.json();return{ok:!0,value:t}},T=async(e,t,r)=>{let{fetch:o}=d(r??{}),n=A(e,t,r),s=await o(n);return await F(s)};T.toRequest=A;T.fromResponse=F;var q=(e,t)=>{let{sid:r,hostName:o,sort:n,limit:s,skip:i}=d(t??{}),c=new URLSearchParams;n!==void 0&&c.append("sort",n),s!==void 0&&c.append("limit",${s}),i!==void 0&&c.append("skip",${i});let a=https://${o}/api/pages/${e}?${c.toString()};return new Request(a,r?{headers:{Cookie:f(r)}}:void 0)},_=async e=>{if(!e.ok)return g(e);let t=await e.json();return{ok:!0,value:t}},K=async(e,t)=>{let{fetch:r}=d(t??{}),o=await r(q(e,t));return await _(o)};K.toRequest=q;K.fromResponse=_;var z=(e,t)=>{let{sid:r,hostName:o}=d(t??{});return new Request(https://${o}/api/projects/${e},r?{headers:{Cookie:f(r)}}:void 0)},G=async e=>{if(!e.ok)return g(e);let t=await e.json();return{ok:!0,value:t}},I=async(e,t)=>{let{fetch:r}=d(t??{}),o=z(e,t),n=await r(o);return G(n)};I.toRequest=z;I.fromResponse=G;var W=(e,t)=>{let{sid:r,hostName:o}=d(t??{}),n=new URLSearchParams;for(let s of e)n.append("ids",s);return new Request(https://${o}/api/projects?${n.toString()},r?{headers:{Cookie:f(r)}}:void 0)},Q=async e=>{if(!e.ok)return g(e);let t=await e.json();return{ok:!0,value:t}},Y=async(e,t)=>{let{fetch:r}=d(t??{}),o=await r(W(e,t));return Q(o)};Y.toRequest=W;Y.fromResponse=Q;var X=(e,t)=>{if(!(e instanceof HTMLDivElement))throw new TypeError("${t}" must be HTMLDivElememt but actual is "${e}")};var V=()=>ge(document.getElementsByClassName("status-bar")?.0,"div.status-bar"),ge=(e,t)=>{if(!!e)return X(e,t),e};var P=e=>new Promise(t=>setTimeout(()=>t(),e));var Z=()=>{let e=V();if(!e)throw new Error("div.status-bar can't be found");let t=document.createElement("div");return e.append(t),{render:(...r)=>{t.textContent="";let o=ee(...r);o&&t.append(o)},dispose:()=>t.remove()}},ee=(...e)=>{let t=e.flatMap(o=>{switch(o.type){case"spinner":returnEe();case"check-circle":returnbe();case"exclamation-triangle":returnke();case"text":returnN(o.text);case"group":{let n=ee(...o.items);return n?n:[]}}});if(t.length===0)return;if(t.length===1)return t0;let r=document.createElement("span");return r.classList.add("item-group"),r.append(...t),r},N=e=>{let t=document.createElement("span");return t.classList.add("item"),t.append(e),t},Ee=()=>{let e=document.createElement("i");return e.classList.add("fa","fa-spinner"),N(e)},be=()=>{let e=document.createElement("i");return e.classList.add("kamon","kamon-check-circle"),N(e)},ke=()=>{let e=document.createElement("i");return e.classList.add("fas","fa-exclamation-triangle"),N(e)};var Le="4.2.0";async function h(){let t=(await Te())("https://scrapbox.io",{reconnectionDelay:5e3,transports:["websocket"]});return await new Promise((r,o)=>{let n=s=>o(s);t.once("connect",()=>{t.off("disconnect",n),r()}),t.once("disconnect",n)}),t}function Te(){let e=https://cdnjs.cloudflare.com/ajax/libs/socket.io/${Le}/socket.io.min.js;if(document.querySelector(script[src="${e}"]))return Promise.resolve(window.io);let t=document.createElement("script");return t.src=e,new Promise((r,o)=>{t.onload=()=>r(window.io),t.onerror=n=>o(n),document.head.append(t)})}function y(e,t=9e4){function r(n,s){let i;return new Promise((c,a)=>{let p=l=>{clearTimeout(i),a(new Error(l))};e.emit(n,s,l=>{clearTimeout(i),e.off("disconnect",p),l.error&&a(new Error(JSON.stringify(l.error))),"data"in l?c(l?.data):c(void 0)}),i=setTimeout(()=>{e.off("disconnect",p),a(new Error(Timeout: exceeded ${t}ms))},t),e.once("disconnect",p)})}async function*o(...n){let s,i=()=>new Promise(a=>s=a),c=a=>{s?.(a)};for(let a of n)e.on(a,c);try{for(;;)yield await i()}finally{for(let a of n)e.off(a,c)}}return{request:r,response:o}}var te=()=>h(),v=async e=>{if(e.connected)return;let t=new Promise(r=>e.once("connect",()=>r()));e.connect(),await t},x=async e=>{if(e.disconnected)return;let t=new Promise(r=>{let o=n=>{n==="io client disconnect"&&(r(),e.off("disconnect",o))};e.on("disconnect",o)});e.disconnect(),await t};var R,S=async()=>{if(R!==void 0)return R;let e=await j();if(e.isGuest)throw new Error("this script can only be executed by Logged in users");return R=e.id,R},re=new Map,L=async e=>{let t=re.get(e);if(t!==void 0)return t;let r=await I(e);if(!r.ok){let{name:n,message:s}=r.value;throw new Error(${n} ${s})}let{id:o}=r.value;return re.set(e,o),o};var u=(e,{parseOnNested:t,parseOnQuoted:r,patterns:o})=>(n,s,i)=>{var c,a,p,l,C,O;if(!t&&s.nested)return(c=i?.())!==null&&c!==void 0?c:[];if(!r&&s.quoted)return(a=i?.())!==null&&a!==void 0?a:[];for(let ae of o){let k=ae.exec(n);if(k===null)continue;let ce=n.substring(0,k.index),pe=n.substring(k.index+((l=(p=k0)===null||p===void 0?void 0:p.length)!==null&&l!==void 0?l:0)),de=e((C=k0)!==null&&C!==void 0?C:"",s);return...E(ce,s),...de,...E(pe,s)}return(O=i?.())!==null&&O!==void 0?O:[]},m=e=>{type:"plain",raw:e,text:e},Ie=u(m,{parseOnNested:!0,parseOnQuoted:!0,patterns:/^()(.*)()$/}),Pe=/^>.*$/,Ne=(e,t)=>t.context==="table"?m(e,t):{type:"quote",raw:e,nodes:E(e.substring(1),{...t,quoted:!0})},Re=u(Ne,{parseOnNested:!1,parseOnQuoted:!1,patterns:Pe}),Se=/^\? .+$/,Me=(e,t)=>t.context==="table"?m(e,t):{type:"helpfeel",raw:e,text:e.substring(2)},Ce=u(Me,{parseOnNested:!1,parseOnQuoted:!1,patterns:Se}),Oe=/\[\[https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)\]\]/i,je=/\[\[https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}\]\]/,De=(e,t)=>{if(t.context==="table")return m(e,t);let r=e.substring(2,e.length-2),o=/^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}$/.test(r);return[{type:"strongImage",raw:e,src:o?${r}/thumb/1000:r}]},$e=u(De,{parseOnNested:!1,parseOnQuoted:!0,patterns:Oe,je}),He=/\^[\*\.icon(?:\*1-9\d*)?\]/;function oe(e){return(t,r)=>{if(e==="strongIcon"&&r.context==="table")return m(t,r);let o=e==="icon"?t.substring(1,t.length-1):t.substring(2,t.length-2),n=o.lastIndexOf(".icon"),s=o.substring(0,n),i=s.startsWith("/")?"root":"relative",c=o.substring(n+5,o.length),a=c.startsWith("*")?parseInt(c.substring(1),10):1;return new Array(a).fill({}).map(()=>({path:s,pathType:i,type:e,raw:t}))}}var Ue=oe("icon"),Be=u(Ue,{parseOnNested:!0,parseOnQuoted:!0,patterns:He}),Ae=/\[\^[\*\.icon(?:\*\d+)?\]\]/,Fe=oe("strongIcon"),qe=u(Fe,{parseOnNested:!1,parseOnQuoted:!0,patterns:Ae}),_e=/\[\[(?:[^[]|\^[]).*?\]*\]\]/,Ke=(e,t)=>t.context==="table"?m(e,t):{type:"strong",raw:e,nodes:E(e.substring(2,e.length-2),{...t,nested:!0})},ze=u(Ke,{parseOnNested:!1,parseOnQuoted:!0,patterns:_e}),Ge=/\\$ .+? \/,We=/\[\$ [^\+\]/,Qe=(e,t)=>t.context==="table"?m(e,t):{type:"formula",raw:e,formula:e.substring(3,e.length-(e.endsWith(" ")?2:1))}],Ye=u(Qe,{parseOnNested:!1,parseOnQuoted:!0,patterns:Ge,We}),Xe=/\!"#%&'()*+,\-./{|}<>_~]+ (?:\[[^[\+\]|^\])+\]/,Ve=(e,t)=>{if(t.context==="table")return m(e,t);let r=e.indexOf(" "),o=e.substring(1,r),n=e.substring(r+1,e.length-1),s=new Set(o);if(s.has("*")){let i=o.split("*").length-1;s.delete("*"),s.add(*-${Math.min(i,10)})}return{type:"decoration",raw:e,rawDecos:o,decos:Array.from(s),nodes:E(n,{...t,nested:!0})}},Je=u(Ve,{parseOnNested:!1,parseOnQuoted:!0,patterns:Xe}),Ze=/.*?/,et=(e,t)=>t.context==="table"?m(e,t):{type:"code",raw:e,text:e.substring(1,e.length-1)},tt=u(et,{parseOnNested:!1,parseOnQuoted:!0,patterns:Ze}),rt=/^$% .+$/,ot=(e,t)=>{var r;if(t.context==="table")return m(e,t);let o=(r=e0)!==null&&r!==void 0?r:"",n=e.substring(2);return{type:"commandLine",raw:e,symbol:o,text:n}},nt=u(ot,{parseOnNested:!1,parseOnQuoted:!1,patterns:rt}),st=/\\s+\/,it=(e,t)=>t.context==="table"?m(e,t):{type:"blank",raw:e,text:e.substring(1,e.length-1)},at=u(it,{parseOnNested:!1,parseOnQuoted:!0,patterns:st}),ct=/\[https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)(?:\?^\\s]+)?(?:\s+https?:\/\/^\s\]+)?\]/i,pt=/\[https?:\/\/^\s\]+\s+https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)(?:\?^\\s]+)?\]/i,dt=/\[https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}(?:\/raw)?(?:\s+https?:\/\/^\s\]+)?\]/,ut=/\[https?:\/\/^\s\]+\s+https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}(?:\/raw)?\]/,mt=e=>/^https?:\/\/^\s\]+\.(png|jpe?g|gif|svg)(\?^\\s]+)?$/i.test(e)||lt(e),lt=e=>/^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}(\/raw)?$/.test(e),ft=(e,t)=>{if(t.context==="table")return m(e,t);let r=e.search(/\s/),o=r!==-1?e.substring(1,r):e.substring(1,e.length-1),n=r!==-1?e.substring(r,e.length-1).trimLeft():"",s,i=mt(n)?n,o:o,n;return[{type:"image",raw:e,src:/^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}$/.test(s)?${s}/thumb/1000:s,link:i}]},gt=u(ft,{parseOnNested:!0,parseOnQuoted:!0,patterns:ct,pt,dt,ut}),ht=/\[https?:\/\/^\s\]+\s+^\]*^\s\]/,xt=/\^[\*^\s\s+https?:\/\/^\s\]+\]/,wt=/\[https?:\/\/^\s\]+\]/,yt=/https?:\/\/^\s+/,Et=(e,t)=>{if(t.context==="table")return m(e,t);let r=e.startsWith("")&&e.endsWith("")?e.substring(1,e.length-1):e,o=/^https?:\/\/^\s\]/.test(r),n=(o?/^https?:\/\/^\s\]+/:/https?:\/\/^\s\]+$/).exec(r);if(n?.0===void 0)return[];let s=o?r.substring(n0.length):r.substring(0,n.index-1);return[{type:"link",raw:e,pathType:"absolute",href:n0,content:s.trim()}]},bt=u(Et,{parseOnNested:!0,parseOnQuoted:!0,patterns:ht,xt,wt,yt}),ne=/\[(^\]*^\s)\s+(NS\d+(?:\.\d+)?,EW\d+(?:\.\d+)?(?:,Z\d+)?)\]/,se=/\[(NS\d+(?:\.\d+)?,EW\d+(?:\.\d+)?(?:,Z\d+)?)(?:\s+(^\]*^\s))?\]/,kt=e=>{lett="",r="",o=""=e.split(","),n=parseFloat(t.replace(/^N/,"").replace(/^S/,"-")),s=parseFloat(r.replace(/^E/,"").replace(/^W/,"-")),i=/^Z\d+$/.test(o)?parseInt(o.replace(/^Z/,""),10):14;return{latitude:n,longitude:s,zoom:i}},vt=(e,t)=>{var r;if(t.context==="table")return m(e,t);let o=(r=e.match(ne))!==null&&r!==void 0?r:e.match(se);if(o===null)return[];let n=e.startsWith("[N")||e.startsWith("[S"),,s="",i=""=n?o:[o0,o2,o1],{latitude:c,longitude:a,zoom:p}=kt(s),l=i!==""?https://www.google.com/maps/place/${encodeURIComponent(i)}/@${c},${a},${p}z:https://www.google.com/maps/@${c},${a},${p}z;return{type:"googleMap",raw:e,latitude:c,longitude:a,zoom:p,place:i,url:l}},Lt=u(vt,{parseOnNested:!1,parseOnQuoted:!0,patterns:ne,se}),Tt=/\[\/?[^\]+\]/,It=e=>{let t=e.substring(1,e.length-1);return{type:"link",raw:e,pathType:t.startsWith("/")?"root":"relative",href:t,content:""}},Pt=u(It,{parseOnNested:!0,parseOnQuoted:!0,patterns:Tt}),Nt=/(?:^|\s)#\S+/,Rt=(e,t)=>{if(t.context==="table")return m(e,t);if(e.startsWith("#"))return{type:"hashTag",raw:e,href:e.substring(1)};let r=e.substring(0,1),o=e.substring(1);return...m(r,t),{type:"hashTag",raw:o,href:o.substring(1)}},St=u(Rt,{parseOnNested:!0,parseOnQuoted:!0,patterns:Nt}),Mt=/^0-9+\. .*$/,Ct=(e,t)=>{if(t.context==="table")return m(e,t);let r=e.indexOf(" "),o=e.substring(0,r-1),n=parseInt(o,10),s=e.substring(r+1,e.length);return{type:"numberList",raw:e,rawNumber:o,number:n,nodes:E(s,{...t,nested:!0})}},Ot=u(Ct,{parseOnNested:!1,parseOnQuoted:!1,patterns:Mt}),jt=(e,t,r)=>{var o;return e===""?[]:(o=r?.())!==null&&o!==void 0?o:[]},Dt=(...e)=>(t,r)=>e.reduceRight((o,n)=>()=>n(t,r,o),()=>Ie(t,r))(),E=Dt(jt,Re,Ce,tt,nt,Ye,at,Je,$e,qe,ze,gt,bt,Be,Lt,Pt,St,Ot);var b=async(e,t)=>{let r=await T(e,t);if(!r.ok)throw new Error(You have no privilege of editing "/${e}/${t}".);let{commitId:o,persistent:n,image:s,links:i,lines:c,id:a,pin:p}=r.value;return{commitId:o,pageId:a,persistent:n,image:s,links:i,pin:p,lines:c}};var U=async(e,t,r)=>t.length===0?{commitId:r.parentId}:await e("socket.io-request",{method:"commit",data:{kind:"page",...r,changes:t,cursor:null,freeze:!0}}),M=async(e,t,{project:r,title:o,retry:n=3,parentId:s,...i})=>{try{s=(await U(e,t,{parentId:s,...i})).commitId}catch{console.log("Faild to push a commit. Retry after pulling new commits");for(let a=0;a<n;a++){let{commitId:p}=await b(r,o);s=p;try{s=(await U(e,t,{parentId:s,...i})).commitId,console.log("Success in retrying");break}catch{continue}}throw Error("Faild to retry pushing.")}return s};var ie=async(e,t,r)=>{let{pageId:o,commitId:n,persistent:s},i,c=await Promise.all(b(e,t),L(e),S());if(!s)return;let a=r?.socket,p=a??await h();await v(p);let{request:l}=y(p);try{await M(l,{deleted:!0},{projectId:i,pageId:o,parentId:n,userId:c,project:e,title:t})}finally{a||await x(p)}};var zi=async e=>{let{render:t,dispose:r}=Z(),o;try{o=await te();let n=0;for(let s of e)await ie(s.project,s.title,{socket:o}),n++,t({type:"spinner"},{type:"text",text:delete ${n}/${e.length} pages...});t({type:"check-circle"},{type:"text",text:deleted ${e.length} pages.})}catch(n){t({type:"exclamation-triangle"},{type:"text",text:n instanceof Error?${n.name} ${n.message}:"Unknown error! (see developper console)"}),console.error(n)}finally{o&&await x(o),await P(1e3),r()}};export{zi as deletePages};