generated at
PDFをGyazoにuploadするUserScript
PDFを画像に変換してGyazoにuploadするscript


使用例
these scripts can be executed on scrapbox.io without bundling.
開発コンソールに直接貼り付けても実行できる
sample.js
await (async () => { const { upload } = await import( "/api/code/takker/PDFをGyazoにuploadするUserScript/main.js" ); const list = await upload({ title: "本の名前", refererURL: "https://example.com", //printResolution: 600, }); console.log(list); // gyazo.jsonが不要ならfalseにする if (true) { const blob = new Blob([JSON.stringify(list)], { type: "application/json" }); const a = document.createElement("a"); a.download = "gyazo.json"; a.src = URL.createObjectURL(blob); document.body.append(a); a.click(); a.remove(); } })();
main.js
import { uploadPDF } from "./mod.js"; export const upload = async (init) => { const list = []; for await (const { index, count, permalink_url } of await uploadPDF(init)) { console.log(`[${index}/${count}] upload ${permalink_url}`); list.push(permalink_url); } return list; };

実装

バグ
created で順番を調節するのを止める
未来の日時にuploadしたことになったりして、画像の閲覧で支障が生じる
uploadしたのに一覧にでなくなったり
ci7lusさんがやっている方法で順番を調整することにする

2025-02-22
10:08:28
PDFの途中からuploadできるようにした
jsrとnpm importに切り替えた
async-libをやめて、deno_std/asyncを使う
2023-02-11
07:10:36
bundle済みコードを貼り付けた
サンプルコードを書き換えた
06:34:13 タイトル変更
もともとは「講義資料PDF uploader」という名前のscriptだった
H1-2022F-1用に即席でこしらえたもの
その後、講義その他で入手したPDF形式の資料や講義スライド講義ノートPDFをgyazoるのに使い続けた
名前が実体にあわなくなったので、「PDFをGyazoにuploadするUserScript」に解明した
2022-05-09
10:11:49 解像度を設定できるようにした
2022-04-20
11:42:14 moduleにして使いやすくした
11:30:09 H1-2022F-1から切り出した
2022-04-17
14:46:53 順番の調整で手こずった
created で順番が決まり、さらに1分刻みでしか変えられないことがわかった
この結果をもとに、うまく順番通りにpdfをあげられるように直した

printResolution 300 を初期値にしてある
$ deno check --remote -r=https://scrapbox.io https://scrapbox.io/api/code/takker/PDFをGyazoにuploadするUserScript/mod.ts
mod.ts
/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> import { pdfConverter } from "../scrapbox-pdftoimage/mod.ts"; import { upload as uploadFile } from "../scrapbox-file-uploader/mod.ts"; import { getGyazoToken } from "jsr:@cosense/std@0.29/rest"; import { upload } from "jsr:@takker/gyazo@0.4"; import { range } from "jsr:@core/iterutil@0.9/range"; import { map } from "jsr:@core/iterutil@0.9/async/map"; import { pooledMap } from "jsr:@std/async@1/pool"; import { getUnixTime } from "npm:date-fns@4/getUnixTime"; import { isErr, unwrapErr, unwrapOk } from "npm:option-t@51/plain_result"; export interface Props { title?: string; refererURL?: string; /** @default {300} */ printResolution?: number; /** @default {1} */ start?: number; }; export const uploadPDF = async (props: Props): Promise<AsyncIterableIterator<{ index: number; count: number; }>> => { // 読み込み const file = await uploadFile({ accept: "application/pdf, *.pdf"}); if (!file) throw new Error("no file specified"); // access token取得 const result = await getGyazoToken(); if (isErr(result)) throw new Error(JSON.stringify(unwrapErr(result))); const accessToken = unwrapOk(result); if (!accessToken) throw new Error("Could not get the access token"); // 画像に変換する const { convert, count } = await pdfConverter(new Uint8Array(await file.arrayBuffer())); return pooledMap( 5, map( range(props?.start ?? 1, count), async (index: number): Promise<[Blob, number]> => [await convert(index, { mimeType: "image/jpeg", printResolution: props?.printResolution ?? 300, quality: 0.95, }), index], ), async ([image, index]): Promise<{ index: number; count: number; }> => { const res = await upload<Response>(image, { created: getUnixTime(new Date()), accessToken, description: `${file.name} ${index}`, ...props, }); if (!res.ok) throw new Error("gyazo error", { cause: res }); return { index, count, ...(await res.json())}; }, ); };

built script
mod.js
var Q=()=>new Promise(e=>{window.pdfjsLib&&e(window.pdfjsLib);let r=setInterval(()=>{window.pdfjsLib&&(clearInterval(r),e(window.pdfjsLib))},1e3)}),X=async e=>{let r=`//cdnjs.cloudflare.com/ajax/libs/pdf.js/${e}/pdf.min.js`;if(!document.querySelector(`script[src="${r}"]`)){let o=document.createElement("script");o.src=r,await new Promise((n,s)=>{o.addEventListener("load",()=>n()),o.addEventListener("error",s),document.body.append(o)});let t=await Q();return t.GlobalWorkerOptions.workerSrc=`//cdnjs.cloudflare.com/ajax/libs/pdf.js/${e}/pdf.worker.min.js`,t}return await Q()};var Z=async(e,r)=>{let o=Array.prototype.getIndexByTitleLc;delete Array.prototype.getIndexByTitleLc;try{let n=await(await X("2.13.216")).getDocument({data:e,cMapUrl:r?.cMapUrl??"https://storage.googleapis.com/chrono-lexica/ci7lus-assets/pdfjs/cmaps/",cMapPacked:!0}).promise,s=await n.getMetadata(),a=async(p,u)=>{let S=await n.getPage(p),k=S.getViewport({scale:window.devicePixelRatio??1.5}),R=document.createElement("canvas"),K=R.getContext("2d");if(!K)throw Error("2D rendering on <canvas> is not supported");let U=(u?.printResolution??150)/72,Ne={canvasContext:K,viewport:k,transform:[U,0,0,U,0,0]};return R.height=Math.floor(k.height*U),R.width=Math.floor(k.width*U),await S.render(Ne).promise,new Promise((we,Fe)=>R.toBlob(J=>J?we(J):Fe(new Error("Faild to create Blob")),u?.mimeType??"image/png",u?.quality))};return{metadata:{info:s.info,metadata:s.metadata},count:n.numPages,convert:(p,u)=>a(Math.min(Math.max(1,p),n.numPages),u),read:async function*(p){for(let u=1;u<=n.numPages;u++)yield await a(u,p)}}}finally{Array.prototype.getIndexByTitleLc=o}};function ee(e){return new Promise((r,o)=>{let t=document.createElement("input");t.type="file",t.accept=e.accept,t.multiple=e.multiple??!1,t.addEventListener("change",()=>{r(e.multiple===!0?t.files?t.files.length===0?void 0:t.files:void 0:t.files?.[0]??void 0)}),t.addEventListener("error",o),t.click()})}function l(e){return e.val}function y(e){return e.err}var re=" must not return ",Pe="`transformer`",be="`recoverer`",Ae="`defaultValue`",P=Pe+re,_="called with ",b=Ae+" must not be ",A=be+re;var Ie="`Ok`",te="`Err`",oe=_+te,ne=_+Ie,Se="Carrying `E` in "+te+" instead of throwing it directly. See `.cause`",V="an instance of `Error` of the current realm.",or="The thrown value is not "+V,nr="The contained E should be "+V,ke="This `.cause` is not "+V;function m(e){return e.ok}function c(e){return{ok:!0,val:e,err:null}}function i(e){return!e.ok}function d(e){return{ok:!1,val:null,err:e}}function f(e){return se(e,oe)}function W(e){return ae(e,ne)}function se(e,r){if(i(e))throw new TypeError(r);return e.val}function ae(e,r){if(m(e))throw new TypeError(r);return e.err}async function E(e,r){if(i(e))return e;let o=l(e),t=await r(o);return c(t)}async function g(e,r){if(m(e))return e;let o=y(e),t=await r(o);return d(t)}var L="`null`",Rt=P+L,Me=_+L,yt=b+L,gt=A+L;var M="`undefined`",_t=P+M,Ce=_+M,Nt=b+M,wt=A+M;var h=e=>e.ok?c(e):d({name:"HTTPError",message:`${e.status} ${e.statusText}`,response:e});var ue=async(e,r)=>{let o=new Request(e,r);try{return c(await globalThis.fetch(o))}catch(t){if(t instanceof DOMException&&t.name==="AbortError")return d({name:"AbortError",message:t.message,request:o});if(t instanceof TypeError)return d({name:"NetworkError",message:t.message,request:o});throw t}};var O=e=>{let{fetch:r=ue,hostName:o="scrapbox.io",...t}=e;return{fetch:r,hostName:o,...t}};var T=e=>`connect.sid=${e}`;function C(e,r={}){if(e===null)return"null";if(Array.isArray(e))return qe(e,r);switch(typeof e){case"string":return JSON.stringify(e);case"bigint":return`${e}n`;case"object":return e.constructor?.name!=="Object"?e.constructor?.name:ve(e,r);case"function":return e.name||"(anonymous)"}return e?.toString()??"undefined"}function qe(e,r){let{threshold:o=20}=r,t=e.map(a=>C(a,r)),n=t.join(", ");if(n.length<=o)return`[${n}]`;let s=t.join(`, `);return`[ ${ce(2,s)} ]`}function ve(e,r){let{threshold:o=20}=r,t=[...Object.keys(e),...Object.getOwnPropertySymbols(e)].map(a=>`${a.toString()}: ${C(e[a],r)}`),n=t.join(", ");if(n.length<=o)return`{${n}}`;let s=t.join(`, `);return`{ ${ce(2,s)} }`}function ce(e,r){let o=" ".repeat(e);return r.split(` `).map(t=>`${o}${t}`).join(` `)}function j(e,r,...o){let t;return Object.defineProperties(e,{name:{get:()=>t||(t=`${r}(${o.map(n=>C(n)).join(", ")})`,t)}})}function me(e){return Array.isArray(e)}function fe(e){return j(r=>me(r)&&r.every(o=>e(o)),"isArrayOf",e)}function D(e){let r=new Set(e);return j(o=>r.has(o),"isLiteralOneOf",e)}function H(e){return e!=null&&!Array.isArray(e)&&typeof e=="object"}function B(e){return typeof e=="string"}var x=async(e,r)=>{let o=e.response.clone(),t=D(r);try{let n=await o.json();if(!H(n))return;if(o.status===422){if(!B(n.message))return;for(let s of["NoQueryError","InvalidURLError"])if(r.includes(s))return{name:s,message:n.message}}return!t(n.name)||!B(n.message)?void 0:n.name==="NotLoggedInError"?!H(n.detals)||!B(n.detals.project)||!fe($e)(n.detals.loginStrategies)?void 0:{name:n.name,message:n.message,details:{project:n.detals.project,loginStrategies:n.detals.loginStrategies}}:{name:n.name,message:n.message}}catch(n){if(n instanceof SyntaxError)return;throw n}},$e=D(["google","github","microsoft","gyazo","email","saml","easy-trial"]);var G="`null` or `undefined`",I=P+G,Ve=_+G,z=b+G,q=A+G;var de=async e=>{let{fetch:r,sid:o,hostName:t,gyazoTeamsName:n}=O(e??{}),s=new Request(`https://${t}/api/login/gyazo/oauth-upload/token${n?`?gyazoTeamsName=${n}`:""}`,o?{headers:{Cookie:T(o)}}:void 0),a=await r(s);return i(a)?a:E(await g(h(f(a)),async p=>await x(p,["NotLoggedInError"])??p),p=>p.json().then(u=>u.token))};var nu=new TextEncoder;var pu=new TextEncoder().encode("0123456789abcdef"),uu=new TextEncoder,cu=new TextDecoder;var $=e=>{let{fetch:r=globalThis.fetch,...o}=e;return{fetch:r,...o}};var Ee=(e,r)=>{let{title:o,description:t,metadataIsPublic:n,collectionId:s,refererURL:a,accessToken:p,created:u,app:S,fetch:k}=$(r),R=new FormData;return R.append("imagedata",e),R.append("access_token",p),a&&R.append("referer_url",a.toString()),S!==void 0&&R.append("app",S),o!==void 0&&R.append("title",o),t!=null&&R.append("desc",t),s&&R.append("collection_id",s),n&&R.append("metadata_is_public","true"),u!==void 0&&R.append("created_at",`${u}`),k("https://upload.gyazo.com/api/upload",{method:"POST",mode:"cors",credentials:"omit",body:R})};function Re(e,r,o){if(o??=e>r?-1:1,!Number.isFinite(e))throw new RangeError(`start must be finite, but got ${e}.`);if(!Number.isFinite(o))throw new RangeError(`step must be finite, but got ${o}.`);if(o===0)throw new RangeError("step must not be 0.");if(!Number.isFinite(r))throw new RangeError(`stop must be finite, but got ${r}.`);if(o>0&&e>r)throw new RangeError("start must be less than stop for positive step.");if(o<0&&e<r)throw new RangeError("start must be greater than stop for negative step.");return function*(){if(o>=0)for(let t=e;t<=r;t+=o)yield t;else for(let t=e;t>=r;t+=o)yield t}()}async function*ye(e,r){let o=0;for await(let t of e)yield await r(t,o++)}var ge="Cannot complete the mapping as an error was thrown from an item";function he(e,r,o){let t=new TransformStream({async transform(n,s){try{let a=await n;s.enqueue(a)}catch(a){a instanceof AggregateError&&a.message===ge&&s.error(a)}}});return(async()=>{let n=t.writable.getWriter(),s=[];try{for await(let a of r){let p=Promise.resolve().then(()=>o(a));n.write(p);let u=p.then(()=>s.splice(s.indexOf(u),1));s.push(u),s.length>=e&&await Promise.race(s)}await Promise.all(s),n.close()}catch{let a=[];for(let p of await Promise.allSettled(s))p.status==="rejected"&&a.push(p.reason);n.write(Promise.reject(new AggregateError(a,ge))).catch(()=>{})}})(),Symbol.asyncIterator in t.readable&&typeof t.readable[Symbol.asyncIterator]=="function"?t.readable[Symbol.asyncIterator]():async function*(){let n=t.readable.getReader();for(;;){let{done:s,value:a}=await n.read();if(s)break;yield a}n.releaseLock()}()}var He=Math.pow(10,8)*24*60*60*1e3,nc=-He;var ze=3600;var Oe=ze*24,sc=Oe*7,Ye=Oe*365.2425,Ke=Ye/12,ac=Ke*3,Y=Symbol.for("constructDateFrom");function Te(e,r){return typeof e=="function"?e(r):e&&typeof e=="object"&&Y in e?e[Y](r):e instanceof Date?new e.constructor(r):new Date(r)}function xe(e,r){return Te(r||e,e)}function _e(e){return Math.trunc(+xe(e)/1e3)}var bc=async e=>{let r=await ee({accept:"application/pdf, *.pdf"});if(!r)throw new Error("no file specified");let o=await de();if(i(o))throw new Error(JSON.stringify(W(o)));let t=f(o);if(!t)throw new Error("Could not get the access token");let{convert:n,count:s}=await Z(new Uint8Array(await r.arrayBuffer()));return he(5,ye(Re(e?.start??1,s),async a=>[await n(a,{mimeType:"image/jpeg",printResolution:e?.printResolution??300,quality:.95}),a]),async([a,p])=>{let u=await Ee(a,{created:_e(new Date),accessToken:t,description:`${r.name} ${p}`,...e});if(!u.ok)throw new Error("gyazo error",{cause:u});return{index:p,count:s,...await u.json()}})};export{bc as uploadPDF};

#2025-02-22 10:08:22
#2023-02-11 07:12:08
#2023-02-10 21:36:35
#2022-09-13 09:40:00
#2022-08-12 20:38:08
#2022-05-09 10:11:45
#2022-04-20 11:29:34
#2022-04-19 15:29:23
#2022-04-17 15:15:13