JetBrainsDirectLink

Direct download link buttons

  1. // ==UserScript==
  2. // @name JetBrainsDirectLink
  3. // @namespace https://www.jetbrains.com/
  4. // @version 1.0
  5. // @description Direct download link buttons
  6. // @author You
  7. // @match https://www.jetbrains.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=jetbrains.com
  9. // @grant none
  10. // @run-at document-start
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. const path = window.location.pathname.split("/").filter(p => p.length > 0);
  18. if (path.length !== 2 || path[1] !== "download") return;
  19.  
  20. const systems = ["windows", "macos", "linux"];
  21.  
  22. let processDownloads = (downloads) => {
  23. const buttons = systems.reduce((map, name) => (map[name] = document.querySelector(`a[href*="download-thanks.html?platform=${name.substr(0, 3)}"]`), map), {});
  24. const elements = systems.reduce((map, name) => (map[name] = [document.createElement('br')], map), {});
  25. for (const target in downloads) {
  26. const system = systems.find(system => target.startsWith(system.substr(0, 3)));
  27. if (!system) continue;
  28. const button = document.createElement('a');
  29. button.setAttribute('href', downloads[target].link);
  30. button.text = `Download (${target})`;
  31. elements[system].push(button);
  32. elements[system].push(document.createElement('br'));
  33. }
  34. for (const system of systems) {
  35. const elementArray = elements[system];
  36. if (elementArray.length < 2) continue;
  37. let nextElement = buttons[system];
  38. while (!nextElement.parentNode.className.includes('__block'))
  39. nextElement = nextElement.parentNode;
  40. for (const element of elementArray) {
  41. nextElement.parentNode.insertBefore(element, nextElement);
  42. nextElement = element;
  43. }
  44. }
  45. }
  46.  
  47. const openFn = XMLHttpRequest.prototype.open;
  48. XMLHttpRequest.prototype.open = function (...args) {
  49. if (args.length > 1 && typeof args[1] === "string" &&
  50. args[1].startsWith("https://data.services.jetbrains.com/products/releases")) {
  51. XMLHttpRequest.prototype.open = openFn;
  52. fetch(args[1]).then(response => response.json().then(json => {
  53. const process = processDownloads;
  54. if (process != null) {
  55. processDownloads = null;
  56. process(json[Object.keys(json)[0]][0].downloads);
  57. }
  58. }));
  59. }
  60. return openFn.apply(this, args);
  61. }
  62. })();