NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Sketchfab download script // @description lets you download Sketchfab models // @author Reinitialized // //Version Number // @version 1.0 // // Urls process this user script on // @include /^https?://(www\.)?sketchfab\.com/show/.*$/ // ==/UserScript== function getElementByXpath(path) { return document.evaluate(path, document, null, 9, null).singleNodeValue; }; function InfoForGeometry(geom) { try { info = { 'name' : geom._name, 'vertices' : geom.attributes.Vertex._elements, 'primitives' : [] }; for (i = 0; i < geom.primitives.length; ++i) { var primitive = geom.primitives[i]; if (primitive.mode == 1) return null; info.primitives.push({ 'mode' : primitive.mode, 'indices' : primitive.indices._elements }); } return info; } catch (err) { console.log(err.message); console.log(geom); } }; function OBJforGeometry(geom) { return OBJforGeometryInfo(InfoForGeometry(geom)); }; var vertexOffset = 0; var numUndefinedObjNames = 0; function OBJforGeometryInfo(info) { if (!info) return; var obj = 'o ' + (info.name ? info.name : ++numUndefinedObjNames) + '\n'; for (var i = 0; i < info.vertices.length; i += 3) { obj += 'v '; for (j = 0; j < 3; ++j) { obj += info.vertices[i + j] + ' '; } obj += '\n'; } for (var i = 0; i < info.primitives.length; ++i) { var primitive = info.primitives[i]; if (primitive.mode == gl.TRIANGLES || primitive.mode == gl.TRIANGLE_STRIP) { for (j = 0; j + 2 < primitive.indices.length; primitive.mode == gl.TRIANGLES ? j += 3 : ++j) { obj += 'f '; for (k = 0; k < 3; ++k) { obj += (primitive.indices[j + k] + vertexOffset + 1) + ' '; } obj += '\n'; } } else { console.log('Primitive mode not implemented'); } } vertexOffset += info.vertices.length / 3; return obj; }; var computedIDs = new Array(); var combinedOBJ = ''; function recurse(node) { if (node.className() == 'Geometry') { var computeOBJ = true; var useID = '_uniqueID' in node; for (var i = 0; i < computedIDs.length; ++i) { if (computedIDs[i] == (useID ? node._uniqueID : node._name)) { computeOBJ = false; break; } } if (computeOBJ) { computedIDs.push(useID ? node._uniqueID : node._name); combinedOBJ += OBJforGeometry(node); } } if (node.children.length) { for (var i = 0; i < node.children.length; ++i) { recurse(node.children[i]); } } }; window.dlOBJ = function() { recurse(view3D._scene); // Credit: http://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/ function destroyClickedElement(event) { document.body.removeChild(event.target); } var textToWrite = combinedOBJ; var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'}); // Credit: http://phpjs.org/functions function basename (path, suffix) { var b = path.replace(/^.*[\/\\]/g, ''); if (typeof suffix === 'string' && b.substr(b.length - suffix.length) == suffix) { b = b.substr(0, b.length - suffix.length); } return b; } var fileNameToSaveAs = basename(document.URL) + ".obj"; var downloadLink = document.createElement("a"); downloadLink.download = fileNameToSaveAs; downloadLink.innerHTML = "Download File"; if (window.webkitURL != null) { // Chrome allows the link to be clicked // without actually adding it to the DOM. downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob); } else { // Firefox requires the link to be added to the DOM // before it can be clicked. downloadLink.href = window.URL.createObjectURL(textFileAsBlob); downloadLink.onclick = destroyClickedElement; downloadLink.style.display = "none"; document.body.appendChild(downloadLink); } downloadLink.click(); }; var ul = getElementByXpath('//*[@id="main-menu"]/ul'); var li=document.createElement("li"); li.innerHTML='<a class="order-model" id="downloadOBJ"><span>Download .OBJ</span></a>'; li.addEventListener ("click", dlOBJ , false); ul.appendChild(li);