JetBra

Add a button on the plugin homepage and click to get the plugin activation code

当前为 2024-03-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name JetBra
  3. // @namespace https://github.com/novice88/jetbra
  4. // @version 3.2
  5. // @license MIT
  6. // @description Add a button on the plugin homepage and click to get the plugin activation code
  7. // @author novice.li
  8. // @match https://plugins.jetbrains.com/*
  9. // @grant GM_setClipboard
  10. // @grant GM_addStyle
  11. // @grant GM_xmlhttpRequest
  12. // @grant window.onurlchange
  13. // @connect noviceli.win
  14. // @connect self
  15. // @connect localhost
  16. // ==/UserScript==
  17.  
  18.  
  19. async function findElementWithRetry(cssSelector) {
  20. const maxAttempts = 50;
  21. for (let attempts = 0; attempts < maxAttempts; attempts++) {
  22. const element = document.querySelector(cssSelector);
  23. if (element) {
  24. return element;
  25. }
  26. await new Promise(resolve => setTimeout(resolve, 100));
  27. }
  28. throw new Error(`Element with selector '${cssSelector}' not found after ${maxAttempts} attempts.`);
  29. }
  30.  
  31. let addButton = async function () {
  32. console.log('JetBra is running');
  33. 'use strict';
  34. GM_addStyle(`
  35. .jetbra-button {
  36. background-color: #04AA6D;
  37. border: none;
  38. color: white;
  39. padding: 8px 24px;
  40. text-align: center;
  41. text-decoration: none;
  42. display: inline-block;
  43. border-radius: 16px;
  44. box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  45. transition-duration: 0.4s;
  46. }
  47.  
  48. .jetbra-button:hover {
  49. background-color: #057e47;
  50. color: white;
  51. }
  52. `);
  53. const backendBaseUrl = 'https://jetbra.noviceli.win'
  54.  
  55. // 获取插件的 id
  56. // 如果当前url满足 https://plugins.jetbrains.com/plugin/<pluginId>-xxx 的格式,就直接从url中获取
  57. let url = window.location.href
  58. if (!url.startsWith('https://plugins.jetbrains.com/plugin/')) {
  59. return;
  60. }
  61. // 提取 pluginId
  62. let pluginId = url.split('/')[4].split('-')[0]
  63. console.log('pluginId: ' + pluginId);
  64.  
  65. let pluginDetail = await fetch('https://plugins.jetbrains.com/api/plugins/' + pluginId).then(r => r.json());
  66.  
  67. const parentElement = await findElementWithRetry('.plugin-header__controls-panel > div:first-child');
  68.  
  69. // 如果 parentElement 的孩子中已经有了按钮,就不再添加
  70. if (parentElement.querySelector('.jetbra-button')) {
  71. return;
  72. }
  73. let newElement = document.createElement('div');
  74. newElement.classList.toggle('wt-col-inline');
  75. newElement.innerHTML = `<button class="jetbra-button" type="button">CLICK TO GENERATE ACTIVATION CODE</button>`;
  76. parentElement.appendChild(newElement)
  77.  
  78. newElement.addEventListener('click', async () => {
  79. if (pluginDetail.purchaseInfo === undefined) {
  80. window.alert('This plugin is not a paid plugin in the market');
  81. return;
  82. }
  83. let data = {
  84. "licenseeName": "reborn",
  85. "assigneeName": "reborn",
  86. "assigneeEmail": "",
  87. "licenseRestriction": "",
  88. "checkConcurrentUse": false,
  89. "products": [{
  90. "code": pluginDetail.purchaseInfo.productCode,
  91. "fallbackDate": "2026-12-30",
  92. "paidUpTo": "2026-12-30",
  93. "extended": false
  94. }],
  95. "metadata": "0120230102PPAA013009",
  96. "hash": "41472961/0:1563609451",
  97. "gracePeriodDays": 7,
  98. "autoProlongated": true,
  99. "isAutoProlongated": true
  100. }
  101. GM_xmlhttpRequest({
  102. method: 'POST',
  103. url: backendBaseUrl + '/generateLicense',
  104. headers: {
  105. 'Content-Type': 'application/json'
  106. },
  107. data: JSON.stringify(data),
  108. onload: function (response) {
  109. let license = JSON.parse(response.responseText).license
  110. GM_setClipboard(license, 'text');
  111. window.alert('The activation code has been copied to your clipboard');
  112. }
  113. });
  114. })
  115. };
  116.  
  117. addButton();
  118. if (window.onurlchange === null) {
  119. window.addEventListener('urlchange', (info) => {
  120. addButton();
  121. });
  122. }