Greasy Fork 支持 简体中文。

fab.com Filtros Extras

Custom automated filter/gather script to simplify the process of adding new models from fab.com to your account, be aware that the server has a limit on how many you will be able to add to your account, and then you will have to wait to get your HTTP 429 error gone.

  1. // ==UserScript==
  2. // @name fab.com Filtros Extras
  3. // @license MIT
  4. // @namespace http://tampermonkey.net/
  5. // @version 2024-11-02
  6. // @description Custom automated filter/gather script to simplify the process of adding new models from fab.com to your account, be aware that the server has a limit on how many you will be able to add to your account, and then you will have to wait to get your HTTP 429 error gone.
  7. // @author 0x01x02x03
  8. // @match https://www.fab.com/listings/*
  9. // @match https://www.fab.com/category/*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=fab.com
  11. // @grant none
  12. // ==/UserScript==
  13. (function() {
  14. 'use strict';
  15.  
  16. function hideOwnedElements() {
  17. const xpath = '//*[@id="root"]/div[1]/main/div/div[2]/div[2]/div[2]/div/ul/li';
  18. const elementsToHideList = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  19.  
  20. for (let i = 0; i < elementsToHideList.snapshotLength; i++) {
  21. const element = elementsToHideList.snapshotItem(i);
  22. if (element && element.textContent && element.textContent.includes("Owned")) {
  23. element.style.display = 'none';
  24. }
  25. }
  26. }
  27.  
  28. function clickAddToMyLibraryButton() {
  29. const xpathResult = document.evaluate('/html/body/div[3]/div[1]/main/div/aside/div/div[2]/div/button[2]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE);
  30. if (xpathResult && xpathResult.singleNodeValue) {
  31. xpathResult.singleNodeValue.click();
  32. window.close();
  33. }
  34. }
  35.  
  36. function clickSpecificElementInExpandableButton() {
  37. const expandableButtons = document.evaluate(
  38. '/html/body/div[3]/div[1]/main/div/aside/div/div[2]/div[1]/div[2]/button',
  39. document,
  40. null,
  41. XPathResult.FIRST_ORDERED_NODE_TYPE,
  42. null
  43. );
  44.  
  45. const expandableButton = expandableButtons.singleNodeValue;
  46. if (expandableButton) {
  47. expandableButton.click();
  48.  
  49. const specificElementXpath = '//div[contains(text(), "For an individual creator or a small team with not more than $100k of revenue or funding in the last 12 months.")]';
  50. const specificElement = document.evaluate(specificElementXpath, expandableButton, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  51.  
  52. if (specificElement && specificElement.singleNodeValue) {
  53. specificElement.singleNodeValue.click();
  54.  
  55. const secondButtonXpath = '/html/body/div[3]/div[1]/main/div/aside/div/div[2]/div[2]/button[2]';
  56. const secondButton = document.evaluate(secondButtonXpath, expandableButton, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  57.  
  58. if (secondButton && secondButton.singleNodeValue) {
  59. secondButton.singleNodeValue.click();
  60. window.close();
  61. }
  62. }
  63. }
  64. }
  65.  
  66. // Use MutationObserver to react to changes in the DOM
  67. const observer = new MutationObserver(hideOwnedElements);
  68. observer.observe(document.getElementById('root'), { childList: true, subtree: true });
  69.  
  70. setInterval(clickAddToMyLibraryButton, 2000);
  71. setInterval(clickSpecificElementInExpandableButton, 2000);
  72. })();