Nexus Mods - Download Mod Faster - Improved UX (All Games)

Improves the user experience for nexusmods.com visitors by adding Insta-DL buttons in various places like |1) categories mod tiles |2) mod description/file page

  1. // ==UserScript==
  2. // @name Nexus Mods - Download Mod Faster - Improved UX (All Games)
  3. // @namespace https://bitbucket.org/antonolsson91/nexus-mods-stardew-valley-improved-ux/
  4. // @version 1.6
  5. // @description Improves the user experience for nexusmods.com visitors by adding Insta-DL buttons in various places like |1) categories mod tiles |2) mod description/file page
  6. // @author Anton Olsson, TetteDev
  7. // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
  8. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
  9. // @match https://www.nexusmods.com/*/*
  10. // @grant none
  11. // @noframes
  12. // ==/UserScript==
  13.  
  14. (($) => {
  15. const resolveGameId = () => {
  16. try { return parseInt(Object.keys(window.GlobalModStats)[0]); }
  17. catch (err) { debugger; console.error("Could not derive the current game id, please inform the author of this script!", err); return -1; }
  18. };
  19. let DMF = {
  20. STVGameId: resolveGameId(),
  21. startDownload: function (file_id, game_id, btn) {
  22. console.log(`Called startDownload(${file_id},${game_id}, ${btn})`)
  23. $.ajax(
  24. {
  25. type: "POST",
  26. url: "/Core/Libs/Common/Managers/Downloads?GenerateDownloadUrl",
  27. data: {
  28. fid: file_id,
  29. game_id: game_id,
  30. },
  31. success: function (data, error) {
  32. if (data && data.url) {
  33. console.log('Success');
  34. //window.location.href = data.url;
  35. window.open(data.url)
  36. btn.attr("disabled", "true").append(`✅`)
  37. $('.donation-wrapper > p').html('<p>Your download has started</p><p>If you are having trouble, <a href="' + data.url + '">click here</a> to download manually</p>');
  38. } else {
  39. console.trace("Error posting:", error);
  40. }
  41. },
  42. error: function (e) {
  43. console.trace(e);
  44. }
  45. }
  46. );
  47. },
  48. loader: function(){
  49. return $(`
  50. <span><img alt="" width="64" height="64" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K" /></span>
  51. `)
  52. },
  53. initiateDownload: function ( btn_manualDl ) {
  54. console.log("initiateDownload got", btn_manualDl, $(btn_manualDl).attr("href"), $(btn_manualDl).prop("tagName"))
  55.  
  56. let linkParamString = $(btn_manualDl).prop("tagName").toLowerCase() == "a"
  57. ? $(btn_manualDl).attr("href").split("?")[1]
  58. : $(btn_manualDl).find('a').attr("href").split("?")[1]
  59.  
  60. let searchParams = new URLSearchParams(linkParamString)
  61. let id = searchParams.has('file_id')
  62. ? searchParams.get('file_id')
  63. : searchParams.get('id');
  64.  
  65. if( !id) {
  66. id = new URLSearchParams(window.location.href).get("file_id");
  67. if (!id) return false;
  68. }
  69.  
  70. this.startDownload(id, this.STVGameId, btn_manualDl);
  71. },
  72. btn: function(){
  73. this.btn_extended();
  74.  
  75. let btn = $(`<button class="rj-vortex-button">Insta-DL</button>`)
  76. btn.on("click", async (event) => {
  77. event.preventDefault()
  78. let btn_manualDl;
  79.  
  80. if(document.location.href.includes("mods/categories/")){
  81. let current = $(event.target).parents('.mod-tile');
  82. let modUrl = current.find('h3 a').attr('href')
  83.  
  84. let loader = this.loader()
  85. loader.appendTo(current.parent())
  86.  
  87. await $.get(modUrl, source => {
  88. loader.hide()
  89.  
  90. btn_manualDl = $(`<div>${source}</div>`).find('#action-manual');
  91. initiateDownload(btn_manualDl)
  92. });
  93. } else {
  94. let $this = $( event.target )
  95.  
  96. btn_manualDl = $this.data('button')
  97. ? $this.data('button')[0]
  98. : $('#action-manual')
  99. }
  100.  
  101. this.initiateDownload(btn_manualDl)
  102.  
  103. })
  104. return btn;
  105. },
  106. btn_extended: function() {
  107. if (document.querySelector("#bypassFastDownloadButton")) return;
  108.  
  109. let btn = document.createElement("td");
  110. btn.innerHTML = `<button class="rj-vortex-button" id="bypassFastDownloadButton"><span>Insta-DL</span></button>`;
  111. btn.onclick = async (event) => {
  112. event.preventDefault()
  113. let btn_manualDl;
  114.  
  115. if(document.location.href.includes("mods/categories/")){
  116. let current = $(event.target).parents('.mod-tile');
  117. let modUrl = current.find('h3 a').attr('href')
  118.  
  119. let loader = this.loader()
  120. loader.appendTo(current.parent())
  121.  
  122. await $.get(modUrl, source => {
  123. loader.hide()
  124.  
  125. btn_manualDl = $(`<div>${source}</div>`).find('#action-manual');
  126. initiateDownload(btn_manualDl)
  127. });
  128. } else {
  129. let $this = $( event.target )
  130.  
  131. btn_manualDl = $this.data('button')
  132. ? $this.data('button')[0]
  133. : $('#action-manual')
  134. }
  135.  
  136. this.initiateDownload(btn_manualDl)
  137. };
  138.  
  139. try {
  140. const insertionNode = (document.querySelector("#slowDownloadButton") || document.querySelector("#fastDownloadButton")).parentNode.parentNode;
  141. if (!insertionNode) { console.warn("Could not add fast-download button next to the existing download buttons!"); return; }
  142. insertionNode.appendChild(btn);
  143. } catch (err) { }
  144.  
  145. },
  146. main: function(){
  147. // TODO: make this check better in the future
  148. if (!window.location.pathname.includes("/mods/") || window.location.pathname.includes("categories")) return;
  149.  
  150. if (window.DMF.STVGameId == -1) { return; }
  151.  
  152. const isLoggedIn = window["USER_ID"] !== undefined;
  153. if (!isLoggedIn) return;
  154.  
  155. let dl = document.querySelector("#slowDownloadButton");
  156. if (dl) {
  157. dl.removeAttribute("data-download-url");
  158. dl.onclick = () => {
  159. let dlButton = document.querySelector(".rj-vortex-button");
  160. if (!dlButton) {
  161. this.btn();
  162. dlButton = document.querySelector(".rj-vortex-button");
  163. if (!dlButton) { alert("Please use the Insta-Download button instead"); return; }
  164. }
  165. dlButton.click();
  166. };
  167. }
  168.  
  169. if(document.location.href.includes("mods/categories/")){
  170. $('.mod-tile').each( (i, e) => {
  171. $(e).find(".tile-data ul").append(
  172. $(`<li class="inline-flex"></li>`).append(
  173. this.btn()
  174. )
  175. )
  176. } );
  177. } else {
  178. // Header, download latest file
  179. $('#action-manual').parent().append(this.btn())
  180.  
  181.  
  182. // Files tab
  183. $(`.tabcontent-mod-page a.btn.inline-flex`).each((i, e) => {
  184. let p = $(e).parent()
  185. if($(e).html().includes("Manual download")){
  186. p.append(this.btn().data('button', $(e)))
  187. }
  188. })
  189. }
  190.  
  191. }
  192.  
  193. }
  194.  
  195. try {
  196. window.DMF = DMF;
  197. window.DMF.main();
  198. } catch (error) {
  199. debugger;
  200. console.error("Please disable the 'Nexus Mods - Download Mod Faster' userscript as it failed!", error)
  201. alert("Please disable the 'Nexus Mods - Download Mod Faster' userscript as it failed!");
  202. }
  203. })(jQuery);

QingJ © 2025

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