您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add link to download Kotar Books pages into a ZIP file including a book viewer HTML application for use with a web browser (use web browser's zoom feature to zoom in/out pages). Note: that site limits only the first 15 pages for non-free books.
// ==UserScript== // @name Kotar Books Downloader // @namespace https://greasyfork.org/en/users/85671-jcunews // @version 1.0.1 // @license AGPL v3 // @author jcunews // @description Add link to download Kotar Books pages into a ZIP file including a book viewer HTML application for use with a web browser (use web browser's zoom feature to zoom in/out pages). Note: that site limits only the first 15 pages for non-free books. // @match https://school.kotar.cet.ac.il/KotarApp/Viewer.aspx* // @match https://kotar-cet-ac-il.eu1.proxy.openathens.net/KotarApp/Viewer.aspx* // @require https://cdn.jsdelivr.net/gh/nindogo/tiny_zip_js@4fa0ae770e32bac5181c83d8c5c6a9f59f853e12/tiny_zip.js // @grant GM_xmlhttpRequest // @connect kotarimagesstg.cet.ac.il // ==/UserScript== ((em, pgs, dp, dt, ic, dl, rl, pi, pc, dc, tz, ns, fe, ou, z) => { function cl(e) { clearInterval(dt); if (fe && (fe !== 1)) alert(em); dp.remove(); ic && (ic.style.pointerEvents = ""); document.body.style.pointerEvents = "" } function fer(e) { fe = e; if (--dc === 0) cl(e) } function html(s, e) { (e = document.createElement("DIV")).textContent = s; return e.innerHTML } function gi(ii, ct) { if (fe) return; dc++; GM_xmlhttpRequest({ url: `https://kotarimagesstg.cet.ac.il/GetPageImg_v2.ashx?Type=page_img&gPageToken=${pgs[ii].gid}&nStep=${BV_aSizeSteps.length}&nVersion=11`, responseType: "arraybuffer", onload: r => { dc--; ct = r.responseHeaders.split("\r\n").reduce((r, s) => { if (s = s.match(/^\s*content-type\s*:\s*(.*)\s*$/i)) r = s[1]; return r }, 0); tz.add(ns[ii] = `${("000" + (ii + 1)).substr(-4)}-${pgs[ii].pid}${ pgs[ii].lbl ? " " + pgs[ii].lbl.replace(/[\*:\\\|\<\>\/\?]/, "-") : "" }.${ct ? ct.match(/\/(.*)/)[1].replace("jpeg", "jpg") : "png"}`, new Uint8Array(r.response)); if (++pc < dl) { gi(ii + 1) } else { (new Blob([`<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <!-- Downloaded on $(dltime) from: $(gburl) Using Center for Educational Technology (CET) Books Downloader v1.0.1. https://greasyfork.org/en/users/85671-jcunews --> <title>$(title)</title> <style> body{ margin:1.7vw 0 0 0;background:#bbb;overflow:hidden;text-align:center; font-family:sans-serif;font-size:1.2vw; } button,input{ box-sizing:border-box;border-width:.1vw;padding:0 .25vw;height:1.45vw; font:inherit;line-height:1vw; } #tnav{ display:none; } #panel{ position:fixed;left:0;top:0;right:0;border-bottom:.1vw solid #000; box-sizing:border-box;height:1.7vw;background:#ddd; } #lnav{ position:absolute;z-index:1;left:1.0vw;top:.1vw;box-sizing:border-box; border:.1vw solid #55f;border-radius:.3vw;;padding:0 .3vw; line-height:1.3vw;cursor:pointer; } #tnav:checked+#panel #lnav{ border-color:transparent;background:#55f;color:#fff; } #title{ position:absolute;left:6vw;width:36vw;height:1.6vw;overflow:hidden; text-align:left;white-space:nowrap;text-overflow:ellipsis; } #pnc{ display:inline-block;margin-top:.1vw;vertical-align:top; } #pnc button{ margin:0 1vw;width:1.6vw; } #pn{ vertical-align:top;border-width:.1vw;padding-right:0;width:4vw; text-align:right; } #vgb{ position:absolute;right:.3vw;text-decoration:none } #nav{ position:fixed;left:0;top:1.7vw;bottom:0;box-sizing:border-box; border-right:.1vw solid #000;padding-bottom:.4vw;width:6vw; overflow-y:scroll;background:#ddd;counter-reset:pg; } #tnav:not(:checked)~#nav{ display:none; } #nav a{ display:inline-block;margin-top:.4vw;box-sizing:border-box; border:.1vw solid #000;width:4vw;background:#fff; text-decoration:none!important;counter-increment:a; } #nav a:after{ display:block;color:#000;font-size:1vw;line-height:1vw; content:counter(a); } #nav a:hover:after{ background:#bbf; } #nav img{ vertical-align:top;width:100%;object-fit:contain;object-position:0 0; } #pages{ position:fixed;left:6vw;top:1.7vw;right:0;bottom:0;padding-bottom:.4vw; overflow:auto; } #tnav:not(:checked)~#pages{ left:0; } #pages img{ vertical-align:top;margin:.4vw 0 0 .4vw;border:.1vw solid #000; box-sizing:border-box;width:calc(100% - .8vw);background:#fff; object-fit:contain;object-position:0 0; } </style> <style id=css></style> </head> <body> <input id=tnav type=checkbox checked /> <div id=panel> <label id=lnav for=tnav>Nav</label> <div id=title title="$(title2)">$(title2)</div> <div id=pnc> <button id=pp><</button> Page <input id=pn type=number value=1 min=1 max=$(pagemax)/> <button id=np>></button> </div> <a id=vgb href="$(gburl)">View in CET site</a> </div> <div id=nav></div> <div id=pages></div> <script> a = b = ""; "${ns.join("|")}".split("|").forEach((n, i) => { a += \`<a href=#p$[i + 1]><img src="$[n]" /></a>\`; b += \`<img id=p$[i + 1] src="$[n]" />\` }); nav.innerHTML = a; nav.querySelectorAll("A").forEach((e, i) => e.page = i + 1); pages.innerHTML = b; (ps = Array.from(pages.children)).forEach((e, i) => e.page = i + 1); (tnav.onchange = onresize = () => setTimeout(() => { css.innerHTML = \`#pages img{width:calc($[pages.offsetWidth - pages.offsetTop * 2]px * $[devicePixelRatio])}\` }, 0))(); pn.oninput = e => (e = nav.querySelector(\`a[href="#p$[pn.value]"]\`)) && e.click(); pages.onscroll = (vh, st, pm) => { vh = pages.offsetHeight / 2; st = pages.scrollTop; pm = ps[0].offsetTop; ps.some(e => { if ((st >= (e.offsetTop - pm - vh)) && (st < (e.offsetTop + e.offsetHeight - vh))) { pn.value = e.page; return true } }) }; addEventListener("keydown", ev => { if (!ev.altKey && !ev.ctrlKey && !ev.shiftKey) switch (ev.key) { case "ArrowLeft": pp.click() break; case "ArrowRight": np.click() break; } }); addEventListener("click", (ev, e) => { switch ((e = ev.target).id) { case "pp": pn.oninput(pn.value = pn.value > 1 ? parseInt(pn.value) - 1 : 1); break; case "np": if (document.querySelector("#p" + (e = (p = parseInt(pn.value)) + 1))) { pn.oninput(pn.value = e); if (parseInt(pn.value) <= e) pn.oninput(pn.value = e + 2) } break; default: if (e.matches("#nav *")) { if (!e.href) e = e.parentNode; document.querySelector(e.hash).scrollIntoView(); pages.scrollBy(0, -pages.children[0].offsetTop); ev.preventDefault(pn.value = e.page) } } onfocus() }); onfocus = () => { if (!document.activeElement || (document.activeElement.id !== "pn")) pages.focus() }; onload = () => setTimeout(() => pages.onscroll(onresize(pages.focus())), 0) </script> </body> </html>`.replace(/\$\(dltime\)/g, (new Date).toGMTString() ).replace(/\$\(gburl\)/g, location.href.match(/^[^#]+/)[0] ).replace(/\$\(title\)/, b = document.title.match(/קראו בכותר - (.*)/u)[1] ).replace(/\$\(title2\)/g, html(b) ).replace(/\$\(pagemax\)/, pgs.length ).replace(/\$\[([^\]]+)\]/g, "${$1}" )], {type: "text/html"})).arrayBuffer().then(a => { tz.add("viewer.html", new Uint8Array(a)); if (ou) URL.revokeObjectURL(ou); (ct = document.createElement("A")).href = ou = URL.createObjectURL(tz.generate()); ct.download = `${b}.zip`; ct.style.display = "none"; document.body.appendChild(ct).click(); ct.remove(); cl() }) } }, onerror: fer }) } function nx(av) { try { if (!confirm( `Book only has ${pgs.length} accessible page(s)${pgs.length !== oPagesInfo.pages.length ? ` out of ${oPagesInfo.pages.length} pages` : ""}. Rough estimated download size is ${ (() => { if (av >= 1024*1048576) { return parseFloat((av / 1024*1048576).toFixed(2)) + "GB" } else if (av >= 1048576) { return parseFloat((av / 1048576).toFixed(2)) + "MB" } else return parseFloat((av / 1024).toFixed(2)) + "KB" })() } based on ${rl.length} already loaded page(s). \nProceed with the download?`)) return; dl = pgs.length; rl = Math.ceil(dl / 4); pi = 0; pc = 0; dc = 0; tz = new tiny_zip; ns = []; document.body.style.pointerEvents = "none"; dpp.textContent = `Retrieving pages (1/${dl})...`; document.documentElement.append(dp); dt = setInterval(() => (dpp.textContent = `Retrieving pages (${pc}/${dl})...`), 100); gi(0) } catch(z) { alert(em, cl()) } } em = "Center for Educational Technology (CET) Books Downloader\n\nFailed to retrieve data due to site changes."; (function wt() { if (!(ic = document.querySelector(".toolbarusermenu"))) return setTimeout(wt, 200); ic.insertAdjacentHTML("afterend", '<li style="float:left;margin:1em 0 0 2em"><a href="javascript:void(0)" style="font-size:12pt;text-decoration:none">Download book</a></li>'); (ic = ic.nextElementSibling).onclick = function() { try { this.style.pointerEvents = "none"; if (!(rl = document.querySelectorAll('.BV_oImage[style*="background-image"]')).length) throw 0; pgs = oPagesInfo.pages.slice(0, oPagesInfo.pages.findIndex(o => o.gid === "00000000-0000-0000-0000-000000000000") || undefined); rl.forEach(e => e.url = e.style.backgroundImage.match(/"([^"]+)"/)[1]); (dp = document.createElement("DIV")).id = "cbdujs"; dp.innerHTML = `<style> #cbdujs{all:revert;position:fixed;z-index:999;left:0;top:0;right:0;bottom:0;background:#0007} #cbdujspop{ position:absolute;left:50%;top:50%;transform:translate(-50%); border:.2em solid #00b;border-radius:.5em;padding:.5em 1em;background:#fff;font-family:sans-serif; } </style><div id="cbdujspop"></div>`; dpp = dp.lastChild; dl = 0; (function gii(this_, i) { GM_xmlhttpRequest({url: rl[i].url, method: "HEAD", onload: r => { dl += parseInt(r.responseHeaders.split("\r\n").reduce((r, s) => { if (s = s.match(/^\s*content-length\s*:\s*(\d+)\s*$/i)) r = parseInt(s[1]); return r }, 0)); if (++i < rl.length) { gii(this_, i) } else { this_.style.pointerEvents = ""; nx(dl / rl.length * pgs.length) } }, onerror: e => { this_.style.pointerEvents = ""; fer(e) }}) })(this, 0) } catch(z) { alert(em); this.style.pointerEvents = "" } } })() })()