Greasy Fork镜像 支持简体中文。

Pixiv Show Request Price

For each artwork on Pixiv, show the request price if available and sort artworks by price.

  1. // ==UserScript==
  2. // @name Pixiv Show Request Price
  3. // @author MahdeenSky
  4. // @namespace http://tampermonkey.net/
  5. // @version 1.0
  6. // @description For each artwork on Pixiv, show the request price if available and sort artworks by price.
  7. // @match https://www.pixiv.net/request/creators/works/illust
  8. // @match https://www.pixiv.net/request/creators/works/illust?*
  9. // @match https://www.pixiv.net/bookmark_new_illust.php
  10. // @match https://www.pixiv.net/discovery
  11. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant none
  13. // @license GNU GPLv3
  14. // ==/UserScript==
  15.  
  16. (function () {
  17. "use strict";
  18.  
  19. const button = document.createElement("button");
  20. button.innerText = "Show Request Price (0/0)";
  21. button.style.position = "fixed";
  22. button.style.bottom = "10px";
  23. button.style.left = "10px";
  24. button.style.zIndex = "9999";
  25. button.style.padding = "10px";
  26. button.style.backgroundColor = "blue";
  27. button.style.color = "white";
  28. button.style.border = "none";
  29. button.style.borderRadius = "5px";
  30. button.style.cursor = "pointer";
  31. document.body.appendChild(button);
  32.  
  33. const sortButton = document.createElement("button");
  34. sortButton.innerText = "Sort by Price";
  35. sortButton.style.position = "fixed";
  36. sortButton.style.bottom = "50px";
  37. sortButton.style.left = "10px";
  38. sortButton.style.zIndex = "9999";
  39. sortButton.style.padding = "10px";
  40. sortButton.style.backgroundColor = "green";
  41. sortButton.style.color = "white";
  42. sortButton.style.border = "none";
  43. sortButton.style.borderRadius = "5px";
  44. sortButton.style.cursor = "pointer";
  45. document.body.appendChild(sortButton);
  46.  
  47. const MAX_PARALLEL_IFRAMES = 2;
  48. let activeIframes = 0;
  49. let globalIndex = 0;
  50. let artistUrls = [];
  51. let artworks = [];
  52. let updatedCount = 0;
  53.  
  54. function updateButtonText() {
  55. button.innerText = `Show Request Price (${updatedCount}/${artworks.length})`;
  56. }
  57.  
  58. function waitForRequestPriceElement(wrapperDiv, iframe, artistUrl, artwork) {
  59. iframe.addEventListener('load', () => {
  60. let requestPriceElement = iframe.contentDocument.querySelector("p.sc-a5e65548-7");
  61. if (requestPriceElement) {
  62. const requestPrice = requestPriceElement.innerText;
  63. console.log(
  64. "######################## " +
  65. artistUrl +
  66. " ##############" +
  67. requestPrice
  68. );
  69. const priceElement = document.createElement("div");
  70. priceElement.classList.add("request-price");
  71. priceElement.innerText = `Request Price: ${requestPrice}`;
  72. priceElement.style.backgroundColor = "#f0f0f0";
  73. priceElement.style.color = "#333";
  74. priceElement.style.padding = "10px";
  75. priceElement.style.marginBottom = "10px";
  76. priceElement.style.border = "1px solid #ccc";
  77. priceElement.style.borderRadius = "5px";
  78. priceElement.style.fontSize = "14px";
  79. priceElement.style.fontWeight = "bold";
  80. priceElement.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.1)";
  81. priceElement.style.opacity = "0";
  82. priceElement.style.transition = "opacity 0.5s ease-in-out";
  83. artwork.insertBefore(priceElement, artwork.firstChild);
  84. requestAnimationFrame(() => {
  85. priceElement.style.opacity = "1";
  86. });
  87. updatedCount++;
  88. updateButtonText();
  89. } else {
  90. console.log("Request price element not found, skipping...");
  91. }
  92.  
  93. activeIframes--;
  94. console.log("Active iframes after decrement: " + activeIframes);
  95. processArtist();
  96.  
  97. // reload the iframe then remove the wrapper div
  98. iframe.src = "about:blank";
  99. wrapperDiv.innerHTML = "<iframe style='display: none;'></iframe>";
  100. setTimeout(() => {
  101. wrapperDiv.remove();
  102. }, 1000);
  103. });
  104. }
  105.  
  106. function processArtist() {
  107. if (globalIndex >= artistUrls.length) {
  108. console.log("All artists processed");
  109. return; // All artists processed
  110. }
  111.  
  112. if (activeIframes >= MAX_PARALLEL_IFRAMES) {
  113. console.log("Max parallel iframes reached, retrying...");
  114. setTimeout(processArtist, 100); // Retry after 100ms
  115. return;
  116. }
  117.  
  118. activeIframes++;
  119. console.log("Processing " + artistUrls[globalIndex]);
  120. const artistUrl = artistUrls[globalIndex];
  121. const artwork = artworks[globalIndex];
  122.  
  123. const wrapperDiv = document.createElement("div");
  124. const iframe = document.createElement("iframe");
  125. iframe.style.display = "none";
  126.  
  127. iframe.src = artistUrl + "/request";
  128. console.log("Visiting " + iframe.src);
  129. globalIndex++;
  130.  
  131. wrapperDiv.appendChild(iframe);
  132. document.body.appendChild(wrapperDiv);
  133.  
  134. waitForRequestPriceElement(wrapperDiv, iframe, artistUrl, artwork);
  135. }
  136.  
  137. function scrapeArtworks() {
  138. // do a case by case check for different kind of css selectors for artworks
  139. const selectors = ["li.PKpFw", "li.kFAPOq"];
  140. let selector = null;
  141. if (document.querySelector(selectors[0])) {
  142. selector = selectors[0];
  143. } else if (document.querySelector(selectors[1])) {
  144. selector = selectors[1];
  145. } else {
  146. console.error("No artworks found");
  147. return { artistUrls: [], artworks: [] };
  148. }
  149.  
  150. const artworks = document.querySelectorAll(selector);
  151. const artistUrls = [];
  152.  
  153. artworks.forEach((artwork) => {
  154. // Check if the artwork already has the price element with the class "request-price"
  155. const existingPriceElement = artwork.querySelector('.request-price');
  156. if (existingPriceElement) {
  157. return; // Skip this artwork if it already has the price
  158. }
  159. let selector = "a.sc-1rx6dmq-2";
  160. if (document.querySelector("a.pPtWa")) {
  161. selector = "a.pPtWa";
  162. }
  163.  
  164. const artistLink = artwork.querySelector(selector);
  165. const artistUrl = artistLink.href;
  166.  
  167. artistUrls.push(artistUrl);
  168. });
  169.  
  170. return { artistUrls, artworks };
  171. }
  172.  
  173. function getPrices() {
  174. let scrapedData = scrapeArtworks();
  175. artistUrls = scrapedData.artistUrls;
  176. artworks = scrapedData.artworks;
  177.  
  178. updateButtonText(); // Update button text with initial counts
  179.  
  180. // Start processing up to MAX_PARALLEL_IFRAMES artists initially
  181. for (let i = 0; i < MAX_PARALLEL_IFRAMES; i++) {
  182. setTimeout(processArtist, 300 * i);
  183. }
  184. }
  185.  
  186. function sortArtworksByPrice() {
  187. const artworksContainer = document.querySelector("ul.sc-e6de33c8-0");
  188. const artworksArray = Array.from(document.querySelectorAll("li.sc-9111aad9-0"));
  189.  
  190. const sortedArtworks = artworksArray.sort((a, b) => {
  191. const priceA = parseFloat(a.querySelector(".request-price").innerText.replace(/[^0-9.-]+/g, ""));
  192. const priceB = parseFloat(b.querySelector(".request-price").innerText.replace(/[^0-9.-]+/g, ""));
  193. return priceA - priceB;
  194. });
  195.  
  196. sortedArtworks.forEach((artwork) => {
  197. artworksContainer.appendChild(artwork);
  198. });
  199. }
  200.  
  201. button.addEventListener("click", getPrices);
  202. sortButton.addEventListener("click", sortArtworksByPrice);
  203. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址