Instant Thingverse Download

11/3/2020, 08:00:00 PM

  1. // ==UserScript==
  2. // @name Instant Thingverse Download
  3. // @namespace Violentmonkey Scripts
  4. // @match https://www.thingiverse.com/thing:*
  5. // @grant none
  6. // @version 1.0
  7. // @author -
  8. // @description 11/3/2020, 08:00:00 PM
  9. // ==/UserScript==
  10.  
  11. /**
  12. * From https://github.com/CoeJoder/waitForKeyElements.js
  13. *
  14. * A utility function for userscripts that detects and handles AJAXed content.
  15. *
  16. * Usage example:
  17. *
  18. * function callback(domElement) {
  19. * domElement.innerHTML = "This text inserted by waitForKeyElements().";
  20. * }
  21. *
  22. * waitForKeyElements("div.comments", callback);
  23. * // or
  24. * waitForKeyElements(selectorFunction, callback);
  25. *
  26. * @param {(string|function)} selectorOrFunction - The selector string or function.
  27. * @param {function} callback - The callback function; takes a single DOM element as parameter.
  28. * If returns true, element will be processed again on subsequent iterations.
  29. * @param {boolean} [waitOnce=true] - Whether to stop after the first elements are found.
  30. * @param {number} [interval=300] - The time (ms) to wait between iterations.
  31. * @param {number} [maxIntervals=-1] - The max number of intervals to run (negative number for unlimited).
  32. */
  33. function waitForKeyElements(selectorOrFunction, callback, waitOnce, interval, maxIntervals) {
  34. if (typeof waitOnce === "undefined") {
  35. waitOnce = true;
  36. }
  37. if (typeof interval === "undefined") {
  38. interval = 300;
  39. }
  40. if (typeof maxIntervals === "undefined") {
  41. maxIntervals = -1;
  42. }
  43. var targetNodes = (typeof selectorOrFunction === "function")
  44. ? selectorOrFunction()
  45. : document.querySelectorAll(selectorOrFunction);
  46.  
  47. var targetsFound = targetNodes && targetNodes.length > 0;
  48. if (targetsFound) {
  49. targetNodes.forEach(function(targetNode) {
  50. var attrAlreadyFound = "data-userscript-alreadyFound";
  51. var alreadyFound = targetNode.getAttribute(attrAlreadyFound) || false;
  52. if (!alreadyFound) {
  53. var cancelFound = callback(targetNode);
  54. if (cancelFound) {
  55. targetsFound = false;
  56. }
  57. else {
  58. targetNode.setAttribute(attrAlreadyFound, true);
  59. }
  60. }
  61. });
  62. }
  63.  
  64. if (maxIntervals !== 0 && !(targetsFound && waitOnce)) {
  65. maxIntervals -= 1;
  66. setTimeout(function() {
  67. waitForKeyElements(selectorOrFunction, callback, waitOnce, interval, maxIntervals);
  68. }, interval);
  69. }
  70. }
  71.  
  72.  
  73. const thingMatch = window.location.pathname.match(/thing:(\d+)/);
  74. const thingId = thingMatch[1];
  75.  
  76. waitForKeyElements("a[class*='SidebarMenu__download']", (downloadLink) => {
  77. const downloadButton = downloadLink.querySelector("div")
  78. downloadLink.href = `https://www.thingiverse.com/thing:${thingId}/zip`
  79. downloadButton.parentNode.replaceChild(downloadButton.cloneNode(true), downloadButton);
  80. })