3dsky.org Display More Info

Display more information on the catalog page

  1. // ==UserScript==
  2. // @name 3dsky.org Display More Info
  3. // @namespace HKR
  4. // @match https://3dsky.org/3dmodels*
  5. // @grant none
  6. // @version 1.0
  7. // @author HKR
  8. // @description Display more information on the catalog page
  9. // @run-at document-start
  10. // ==/UserScript==
  11.  
  12. function waitForElement(selector, timeout = 5000) {
  13. return new Promise((resolve, reject) => {
  14. const interval = 100;
  15. const endTime = Date.now() + timeout;
  16.  
  17. const checkExist = setInterval(() => {
  18. const element = document.querySelector(selector);
  19. if (element) {
  20. clearInterval(checkExist);
  21. resolve(element);
  22. } else if (Date.now() > endTime) {
  23. clearInterval(checkExist);
  24. reject(new Error(`Element with selector "${selector}" not found within ${timeout}ms.`));
  25. }
  26. }, interval);
  27. });
  28. }
  29.  
  30. function applyDataToItems(modelsArr) {
  31. modelsArr.forEach(async model => {
  32. const slug = model.slug;
  33. const properties = model.properties;
  34.  
  35. const itemElem = await waitForElement(`a[href="/3dmodels/show/${slug}"]`);
  36. const itemContentElem = itemElem.parentElement.parentElement;
  37.  
  38. const sizeDisplay = properties?.size_kb
  39. ? `<div style='font-size: 1.2em; font-weight: bold; margin-bottom: 4px;'>${(properties.size_kb / 1000) | 0} MB</div>`
  40. : '';
  41.  
  42. const dimensions = (properties?.width || properties?.height || properties?.length)
  43. ? `<div>${properties?.width | 0} x ${properties?.height | 0} x ${properties?.length | 0}</div>`
  44. : '';
  45.  
  46. const customElem = document.createElement('div');
  47. customElem.innerHTML = sizeDisplay + dimensions;
  48. customElem.style.cssText = `
  49. display: flex;
  50. gap: 10px;
  51. align-items: center;
  52. border-top: 1px solid #0000002e;
  53. margin-top: 5px;
  54. padding-top: 5px;
  55. `;
  56.  
  57. itemContentElem.appendChild(customElem);
  58. });
  59. }
  60.  
  61. const originalXHROpen = XMLHttpRequest.prototype.open;
  62.  
  63. XMLHttpRequest.prototype.open = function (method, url, ...rest) {
  64. if (url.includes('https://3dsky.org/api/models')) {
  65. console.log('Intercepted XMLHttpRequest to:', url);
  66.  
  67. this.addEventListener('load', function () {
  68. try {
  69. const responseData = JSON.parse(this.responseText);
  70. const models = responseData?.data?.models;
  71. applyDataToItems(models);
  72. } catch (e) {
  73. console.error('Failed to parse response as JSON:', e);
  74. }
  75. });
  76. }
  77.  
  78. return originalXHROpen.call(this, method, url, ...rest);
  79. };