您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
downloadtextures
// ==UserScript== // @name test_ece_crawl_tex // @version 6.9 // @description downloadtextures // @author yo-mama-duqistudio // @include /^https?://(www\.)?sketchfab\.com/.* // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip-utils/0.0.2/jszip-utils.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js // @run-at document-start // @grant unsafeWindow // @grant GM_download // @license MIT // @namespace https://greasyfork.org/users/1330796 // ==/UserScript== var zip = new JSZip(); let folder = zip.folder("collection"); var button_dw = false; var func_drawGeometry = /(this\._stateCache\.drawGeometry\(this\._graphicContext,t\))/g; var fund_drawArrays = /t\.drawArrays\(t\.TRIANGLES,0,6\)/g; var func_renderInto1 = /A\.renderInto\(n,E,R,n,E,R/g; var func_renderInto2 = /g\.renderInto=function\(e,i,r/g; var func_getResourceImage = /getResourceImage:function\(e,t\){/g; var func_test = /apply:function\(e\){var t=e instanceof r\.Geometry;/g; let resourceReady = false; let resourceTimer = null; function getByteLength(str) { let byteLength = 0; for (let i = 0; i < str.length; i++) { const charCode = str.charCodeAt(i); if (charCode <= 0x7f) { byteLength += 1; } else if (charCode <= 0x7ff) { byteLength += 2; } else if (charCode <= 0xffff) { byteLength += 3; } else { byteLength += 4; } } return byteLength; } var addbtnfunc; (function () { "use strict"; var window = unsafeWindow; console.log("[UserScript]init", window); window.allmodel = []; var saveimagecache2 = {}; var objects = {}; var saveimage_to_list = function (url, file_name) { if (!saveimagecache2[url]) { var mdl = { name: file_name, }; saveimagecache2[url] = mdl; } }; addbtnfunc = function () { var p = document.evaluate( "//div[@class='titlebar']", document, null, 9, null ).singleNodeValue; if (p && !button_dw) { console.log("[UserScript]add btn dwnld"); var btn = document.createElement("a"); btn.setAttribute("class", "control"); btn.innerHTML = "<pre style='font-family:impact;font-size:16px;text-shadow: 1px 1px black;color:#99ff66;'>下载贴图</pre>"; btn.addEventListener("click", () => { alert("Zipping files..."); }); btn.addEventListener("click", dodownload, false); p.appendChild(btn); button_dw = true; waitdownload(); } else { console.log("[UserScript]try add btn later"); setTimeout(addbtnfunc, 3000); } }; var waitdownload = function () { if (!resourceReady) { setTimeout(waitdownload, 500); } else { setTimeout(dodownload, 200); } }; var dodownload = function () { console.log("[UserScript]download"); var idx = 0; window.allmodel.forEach(function (obj) { var mdl = null; }); PackAll(); }; var PackAll = function () { for (var obj in objects) { console.log("[UserScript]save file", obj); folder.file(obj, objects[obj], { binary: true }); } var file_name = document.getElementsByClassName('canvas')[0].getAttribute('data-modeluid'); folder .generateAsync({ type: "blob" }) .then((content) => saveAs(content, file_name + ".zip")); window.top.close(); }; var parseobj = function (obj) { console.log("[UserScript]: obj", obj); var list = []; obj._primitives.forEach(function (p) { if (p && p.indices) { list.push({ mode: p.mode, indices: p.indices._elements, }); } }); var attr = obj._attributes; return { vertex: attr.Vertex._elements, normal: attr.Normal ? attr.Normal._elements : [], uv: attr.TexCoord0 ? attr.TexCoord0._elements : attr.TexCoord1 ? attr.TexCoord1._elements : attr.TexCoord2 ? attr.TexCoord2._elements : attr.TexCoord2 ? attr.TexCoord2._elements : attr.TexCoord3 ? attr.TexCoord3._elements : attr.TexCoord4 ? attr.TexCoord4._elements : attr.TexCoord5 ? attr.TexCoord5._elements : attr.TexCoord6 ? attr.TexCoord6._elements : attr.TexCoord7 ? attr.TexCoord7._elements : attr.TexCoord8 ? attr.TexCoord8._elements : [], primitives: list, }; }; var dosavefile = function (mdl) { var obj = mdl.obj; //console.log("TEST"); //console.log(obj); var str = ""; str += "mtllib " + mdl.name + ".mtl\n"; str += "o " + mdl.name + "\n"; for (var i = 0; i < obj.vertex.length; i += 3) { str += "v "; for (var j = 0; j < 3; ++j) { str += obj.vertex[i + j] + " "; } str += "\n"; } for (i = 0; i < obj.normal.length; i += 3) { str += "vn "; for (j = 0; j < 3; ++j) { str += obj.normal[i + j] + " "; } str += "\n"; } for (i = 0; i < obj.uv.length; i += 2) { str += "vt "; for (j = 0; j < 2; ++j) { str += obj.uv[i + j] + " "; } str += "\n"; } //str += 'usemtl ' + mdl.name + '\n'; str += "s on \n"; var vn = obj.normal.length != 0; var vt = obj.uv.length != 0; for (i = 0; i < obj.primitives.length; ++i) { var primitive = obj.primitives[i]; if (primitive.mode == 4 || primitive.mode == 5) { var strip = primitive.mode == 5; for (j = 0; j + 2 < primitive.indices.length; !strip ? (j += 3) : j++) { str += "f "; var order = [0, 1, 2]; if (strip && j % 2 == 1) { order = [0, 2, 1]; } for (var k = 0; k < 3; ++k) { var faceNum = primitive.indices[j + order[k]] + 1; str += faceNum; if (vn || vt) { str += "/"; if (vt) { str += faceNum; } if (vn) { str += "/" + faceNum; } } str += " "; } str += "\n"; } } else { console.log( "[UserScript]dosavefile: unknown primitive mode", primitive ); } } str += "\n"; var objblob = new Blob([str], { type: "text/plain" }); objects[mdl.name + ".obj"] = objblob; }; window.attachbody = function (obj) { if ( obj._faked != true && ((obj.stateset && obj.stateset._name) || obj._name || (obj._parents && obj._parents[0]._name)) ) { obj._faked = true; if (obj._name == "composer layer" || obj._name == "Ground - Geometry") return; // 用计时器判断资源是否准备好。 if (resourceTimer) { clearTimeout(resourceTimer); console.log("Resource not ready."); } resourceTimer = setTimeout(() => { resourceReady = true; console.log("Resource is ready."); }, 2000); // 根据_instanceID去重复,不然会下载很多次,导致每次下载大小不一样。 let isDuplicate = window.allmodel.some( (existingObj) => existingObj._instanceID === obj._instanceID ); if (!isDuplicate) { window.allmodel.push(obj); } console.log(obj); } //console.log(obj); }; var ParseAllImageList = function (imagemodel) {}; window.hook_test = function (e, idx) { console.log("hooked index: " + idx); console.log(e); }; window.drawhookcanvas = function (e, imagemodel) { // if((e.width == 128 && e.height == 128) || (e.width == 32 && e.height == 32) || (e.width == 64 && e.height == 64)) // { // console.log("texture missed"); // console.log(e); // return e; // } if (imagemodel) { var alpha = e.options.format; var filename_image = imagemodel.attributes.name; if (filename_image == "internal_ground_ao_texture.jpeg") return e; var uid = imagemodel.attributes.uid; var url_image = e.url; var max_size = 0; var obr = e; //let img = imagemodel.attributes.images[imagemodel.attributes.images.length-2]l imagemodel.attributes.images.forEach(function (img) { var alpha_is_check = alpha == "A" ? img.options.format == alpha : true; var d = img.width; while (d % 2 == 0) { d = d / 2; } if (img.size > max_size && alpha_is_check && d == 1) { max_size = img.size; url_image = img.url; uid = img.uid; obr = img; } }); if (!saveimagecache2[url_image]) { if (alpha == "A") { let ext = filename_image.split("."); filename_image = ext[0] + "_alpha." + ext[1]; } saveimage_to_list(url_image, filename_image); } else { //console.log(e); } return obr; } return e; }; window.drawhookimg = function (gl, t) { var url = t[5].currentSrc; var width = t[5].width; var height = t[5].height; if (!saveimagecache2[url]) { //console.log("rejected:"+url); return; } else { //console.log("saved texture:"+url); } var data = new Uint8Array(width * height * 4); gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data); var halfHeight = (height / 2) | 0; var bytesPerRow = width * 4; var temp = new Uint8Array(width * 4); for (var y = 0; y < halfHeight; ++y) { var topOffset = y * bytesPerRow; var bottomOffset = (height - y - 1) * bytesPerRow; temp.set(data.subarray(topOffset, topOffset + bytesPerRow)); data.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow); data.set(temp, bottomOffset); } var canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; var context = canvas.getContext("2d"); var imageData = context.createImageData(width, height); imageData.data.set(data); context.putImageData(imageData, 0, 0); var re = /(?:\.([^.]+))?$/; var ext = re.exec(saveimagecache2[url].name)[1]; var name = saveimagecache2[url].name + ".png"; if (ext == "png" || ext == "jpg" || ext == "jpeg") { var ret = saveimagecache2[url].name.replace("." + ext, ""); name = ret + ".png"; } console.log("saved texture to blob " + name); canvas.toBlob(function (blob) { objects[name] = blob; }, "image/png"); }; })(); (() => { "use strict"; const Event = class { constructor(script, target) { this.script = script; this.target = target; this._cancel = false; this._replace = null; this._stop = false; } preventDefault() { this._cancel = true; } stopPropagation() { this._stop = true; } replacePayload(payload) { this._replace = payload; } }; let callbacks = []; window.addBeforeScriptExecuteListener = (f) => { if (typeof f !== "function") { throw new Error("Event handler must be a function."); } callbacks.push(f); }; window.removeBeforeScriptExecuteListener = (f) => { let i = callbacks.length; while (i--) { if (callbacks[i] === f) { callbacks.splice(i, 1); } } }; const dispatch = (script, target) => { if (script.tagName !== "SCRIPT") { return; } const e = new Event(script, target); if (typeof window.onbeforescriptexecute === "function") { try { window.onbeforescriptexecute(e); } catch (err) { console.error(err); } } for (const func of callbacks) { if (e._stop) { break; } try { func(e); } catch (err) { console.error(err); } } if (e._cancel) { script.textContent = ""; script.remove(); } else if (typeof e._replace === "string") { script.textContent = e._replace; } }; const observer = new MutationObserver((mutations) => { for (const m of mutations) { for (const n of m.addedNodes) { dispatch(n, m.target); } } }); observer.observe(document, { childList: true, subtree: true, }); })(); (() => { "use strict"; window.onbeforescriptexecute = (e) => { var links_as_arr = Array.from(e.target.childNodes); links_as_arr.forEach(function (srimgc) { if (srimgc instanceof HTMLScriptElement) { if ( srimgc.src.indexOf("web/dist/") >= 0 || srimgc.src.indexOf("standaloneViewer") >= 0 ) { e.preventDefault(); e.stopPropagation(); var req = new XMLHttpRequest(); req.open("GET", srimgc.src, false); req.send(""); var jstext = req.responseText; var ret = func_renderInto1.exec(jstext); if (ret) { let index = ret.index + ret[0].length; let head = jstext.slice(0, index); let tail = jstext.slice(index); jstext = head + ",i" + tail; console.log( "[UserScript] Injection: patch_0 injected successful " + srimgc.src ); } ret = func_renderInto2.exec(jstext); if (ret) { let index = ret.index + ret[0].length; let head = jstext.slice(0, index); let tail = jstext.slice(index); jstext = head + ",iin,iir,iid,image_data" + tail; console.log( "[UserScript] Injection: patch_1 injected successful " + srimgc.src ); } ret = fund_drawArrays.exec(jstext); if (ret) { let index = ret.index + ret[0].length; let head = jstext.slice(0, index); let tail = jstext.slice(index); jstext = head + ",window.drawhookimg(t,image_data)" + tail; console.log( "[UserScript] Injection: patch_2 injected successful " + srimgc.src ); } ret = func_getResourceImage.exec(jstext); if (ret) { let index = ret.index + ret[0].length; let head = jstext.slice(0, index); let tail = jstext.slice(index); jstext = head + "e = window.drawhookcanvas(e,this._imageModel);" + tail; console.log( "[UserScript] Injection: patch_3 injected successful " + srimgc.src ); } ret = func_drawGeometry.exec(jstext); if (ret) { let index1 = ret.index + ret[1].length; let head1 = jstext.slice(0, index1); let tail1 = jstext.slice(index1); jstext = head1 + ";window.attachbody(t);" + tail1; console.log( "[UserScript] Injection: patch_4 injected successful" + srimgc.src ); setTimeout(addbtnfunc, 3000); } var obj = document.createElement("script"); obj.type = "text/javascript"; obj.text = jstext; document.getElementsByTagName("head")[0].appendChild(obj); } } }); }; })();