GreasyFork: User Control Panel Button

To add User Control Panel Button into navigation bar

当前为 2023-09-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork: User Control Panel Button
  3. // @namespace UserScripts
  4. // @match https://greasyfork.org/*
  5. // @grant none
  6. // @version 0.1.5
  7. // @license MIT
  8. // @author CY Fung
  9. // @description To add User Control Panel Button into navigation bar
  10. // ==/UserScript==
  11.  
  12. (async () => {
  13.  
  14. function preSetup() {
  15. // for styling
  16.  
  17. let pos = document.querySelectorAll('#site-nav>nav>li.with-submenu');
  18. pos = pos.length >= 1 ? pos[pos.length - 1] : null;
  19.  
  20. if (!pos) return;
  21.  
  22. pos.parentNode.style.minHeight = '2.8rem';
  23.  
  24.  
  25.  
  26.  
  27. return { pos };
  28.  
  29. }
  30.  
  31. function setup(m) {
  32.  
  33. const { cpmRoot } = m;
  34.  
  35.  
  36. let h = (cpmRoot.querySelector('h3') || cpmRoot.querySelector('header'));
  37. if (!h) return;
  38.  
  39. let nav = document.createElement('nav');
  40.  
  41. for (const anchor of cpmRoot.querySelectorAll('li a[href]')) {
  42. let li = nav.appendChild(document.createElement('li'));
  43. li.appendChild(anchor);
  44. }
  45.  
  46.  
  47. let tm = document.createElement('template');
  48. tm.innerHTML = `
  49. <li class="with-submenu" style="display: block;">
  50. <a href="#" onclick="return false">${h.textContent}</a>
  51. <nav>
  52. ${nav.innerHTML}
  53. </nav>
  54. </li>
  55. `.trim();
  56.  
  57. return tm.content;
  58.  
  59.  
  60. }
  61.  
  62.  
  63. function bufferToHex(buffer) {
  64. const byteArray = new Uint8Array(buffer);
  65. const len = byteArray.length;
  66. const hexCodes = new Array(len * 2);
  67. const chars = '0123456789abcdef';
  68. for (let i = 0, j = 0; i < len; i++) {
  69. const byte = byteArray[i];
  70. hexCodes[j++] = chars[byte >> 4];
  71. hexCodes[j++] = chars[byte & 0x0F];
  72. }
  73. return hexCodes.join('');
  74. }
  75.  
  76. async function digestMessage(message) {
  77. const encoder = new TextEncoder("utf-8");
  78. const msgUint8 = encoder.encode(message);
  79. const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8);
  80. return bufferToHex(hashBuffer);
  81. }
  82.  
  83. if (!document.querySelector('.sign-out-link') || document.querySelector('.sign-in-link')) return;
  84.  
  85. let plink = document.querySelector('.user-profile-link');
  86. if (!plink) return;
  87.  
  88. let href = plink.querySelector('a[href*="/users/"]').href;
  89.  
  90. let mi = href.indexOf('/users/');
  91. if (mi < 0) return;
  92.  
  93. if (href.includes('/users/sign')) return;
  94.  
  95.  
  96. let presetup = preSetup();
  97.  
  98. if (!presetup) return;
  99.  
  100. const { pos } = presetup;
  101.  
  102.  
  103. let dm = await digestMessage(href);
  104.  
  105. const stKey = `gf_control_panel_${dm}`
  106.  
  107.  
  108. for (let trialN = 8; trialN--;) {
  109. let s = sessionStorage.getItem(stKey);
  110. let d = typeof s === 'string' ? parseInt(s) : 0;
  111. if (d > 9 && Date.now() - d < 8000) await new Promise(r => setTimeout(r, 320));
  112. else break;
  113. }
  114.  
  115.  
  116. const cpHTML = await new Promise(resolve => {
  117.  
  118.  
  119. let t = sessionStorage.getItem(stKey)
  120.  
  121. if (`${t}`.length > 32) resolve(t);
  122.  
  123.  
  124. sessionStorage.setItem(stKey, `${Date.now()}`);
  125.  
  126.  
  127. fetch(href, {
  128. method: "GET",
  129. mode: "cors",
  130. cache: "force-cache",
  131. credentials: "same-origin",
  132. redirect: "follow",
  133. referrerPolicy: "no-referrer",
  134.  
  135.  
  136. }).then(res => res.text()).then(async res => {
  137.  
  138.  
  139. let template = document.createElement('template');
  140. template.innerHTML = res;
  141. let w = template.content;
  142.  
  143. let cp = w.querySelector('#control-panel');
  144.  
  145. if (!cp) return;
  146.  
  147. const html = cp.innerHTML.trim();
  148.  
  149. sessionStorage.setItem(stKey, html);
  150.  
  151. resolve(html);
  152.  
  153.  
  154. });
  155.  
  156.  
  157.  
  158. });
  159.  
  160. if (!cpHTML || typeof cpHTML !== 'string') return;
  161.  
  162. let cpm = document.createElement('template');
  163.  
  164. cpm.innerHTML = cpHTML;
  165.  
  166. const kc = setup({ cpmRoot: cpm.content, pos });
  167. if (kc) {
  168.  
  169. pos.parentNode.insertBefore(kc, pos.nextSibling);
  170. }
  171.  
  172.  
  173.  
  174. })();