linux.do.level

Linux.Do 查看用户信任级别以及升级条件,数据来源于 https://connect.linux.do

目前為 2024-03-29 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name linux.do.level
  3. // @namespace https://linux.do/u/io.oi/s/level
  4. // @version 1.1.1
  5. // @author LINUX.DO
  6. // @description Linux.Do 查看用户信任级别以及升级条件,数据来源于 https://connect.linux.do
  7. // @icon https://cdn.linux.do/uploads/default/original/1X/de7ee26820e897b6a07350126411ebc489f62202.png
  8. // @match https://linux.do/*
  9. // @grant GM.xmlHttpRequest
  10. // @grant GM_addStyle
  11. // ==/UserScript==
  12.  
  13. (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const o=document.createElement("style");o.textContent=e,document.head.append(o)})(" .level-window{position:fixed;bottom:0;background:var(--secondary);z-index:999;padding:.5em;color:var(--primary);box-shadow:0 0 4px #00000020;border:1px solid var(--primary-low)}.level-window .title .close{width:30px;height:30px;color:#fff;background:red;display:inline-block;text-align:center;line-height:30px;float:right;cursor:pointer;border-radius:4px}.level-window .bg-white{background-color:var(--primary-50);border-radius:.5em;padding:.5em;margin-top:.5em}.level-window h1{color:var(--primary);font-size:1.3rem}.level-window h2{font-size:1.25rem}.mb-4 table tr:nth-child(2n){background-color:var(--tertiary-400)}.level-window .text-red-500{color:#ef4444}.level-window .text-green-500{color:#10b981}.level-window .mb-4 table tr td{padding:4px 8px} ");
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. var _GM = /* @__PURE__ */ (() => typeof GM != "undefined" ? GM : void 0)();
  19. async function getLevelFromConnect() {
  20. return await new Promise((resolve, reject) => {
  21. _GM.xmlHttpRequest({
  22. method: "GET",
  23. url: "https://connect.linux.do",
  24. onload: (response) => {
  25. let regx = /<body[^>]*>([\s\S]+?)<\/body>/i;
  26. let contents = regx.exec(response.responseText);
  27. if (contents) {
  28. const content = contents[1].replace('<a href="/logout" target="_self" class="text-blue-500 hover:underline" title="LINUX DO登录也会退出">退出</a>', "");
  29. resolve({
  30. status: true,
  31. content,
  32. error: ""
  33. });
  34. }
  35. },
  36. onerror: (e) => {
  37. reject({ status: false, error: e.error, content: "" });
  38. }
  39. });
  40. });
  41. }
  42. let levelWindow = void 0;
  43. function createLevelButton() {
  44. const loadingHTML = `
  45. <div class="widget-component-connector">
  46. <a class="icon btn-flat" tabindex="2" title="查看我的等级">
  47. <svg xmlns="http://www.w3.org/2000/svg" width="60px" height="60px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-ring">
  48. <circle cx="50" cy="50" r="30" stroke="#B3B5B4" stroke-width="10" fill="none"/>
  49. <circle cx="50" cy="50" r="30" stroke="#808281" stroke-width="10" fill="none" transform="rotate(144 50 50)">
  50. <animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"/>
  51. <animate attributeName="stroke-dasharray" calcMode="linear" values="18.84955592153876 169.64600329384882;94.2477796076938 94.24777960769377;18.84955592153876 169.64600329384882" keyTimes="0;0.5;1" dur="1" begin="0s" repeatCount="indefinite"/>
  52. </circle>
  53. </svg>
  54. </a>
  55. </div>`;
  56. const defaultHTML = `
  57. <div class="widget-component-connector">
  58. <a class="icon btn-flat" tabindex="2" title="查看我的等级">
  59. <svg class="fa d-icon d-icon-d-chat svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#discourse-sparkles"></use></svg>
  60. </a>
  61. </div>`;
  62. let li = document.createElement("li");
  63. li.className = "header-dropdown-toggle chat-header-icon";
  64. li.setAttribute("id", "level-button");
  65. li.innerHTML = `
  66. <div class="widget-component-connector">
  67. <a class="icon btn-flat" tabindex="2" title="查看我的等级">
  68. <svg class="fa d-icon d-icon-d-chat svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#discourse-sparkles"></use></svg>
  69. </a>
  70. </div>
  71. `;
  72. let loading = false;
  73. li.addEventListener("click", async () => {
  74. if (!loading && !levelWindow) {
  75. loading = true;
  76. li.innerHTML = loadingHTML;
  77. let result = await getLevelFromConnect();
  78. loading = false;
  79. li.innerHTML = defaultHTML;
  80. if (result.status) {
  81. levelWindow = createWindow(result.content);
  82. document.body.appendChild(levelWindow);
  83. } else {
  84. console.error(result.error);
  85. }
  86. } else if (levelWindow && !loading) {
  87. levelWindow.remove();
  88. levelWindow = void 0;
  89. }
  90. });
  91. return li;
  92. }
  93. function createWindow(content) {
  94. let root = document.createElement("div");
  95. root.setAttribute("id", "level-window");
  96. root.className = "level-window";
  97. root.style.right = document.querySelector("div.chat-drawer.is-expanded") ? "430px" : "15px";
  98. root.innerHTML = `
  99. <div class="title">
  100. <span class="close" id="close-button">
  101. <svg class="fa d-icon d-icon-times svg-icon svg-string" xmlns="http://www.w3.org/2000/svg">
  102. <use href="#times"></use>
  103. </svg>
  104. </span>
  105. <div id="content" class="content"></div>
  106. </div>`;
  107. let container = root.querySelector("div#content");
  108. if (container) {
  109. container.innerHTML = content;
  110. }
  111. let close = root.querySelector("span#close-button");
  112. if (close) {
  113. close.addEventListener("click", () => {
  114. root.remove();
  115. levelWindow = void 0;
  116. });
  117. }
  118. let chatContainer = document.querySelector("div.chat-drawer-outlet-container");
  119. if (chatContainer) {
  120. let observer = new MutationObserver((_) => {
  121. let chat = document.querySelector("div.chat-drawer.is-expanded");
  122. root.style.right = chat ? "430px" : "15px";
  123. });
  124. observer.observe(chatContainer, { childList: true });
  125. }
  126. return root;
  127. }
  128. (() => {
  129. let headerObserver = void 0;
  130. function fixSearchButton(titleBar) {
  131. let search = titleBar.childNodes[1];
  132. if (search) {
  133. titleBar.removeChild(search);
  134. titleBar.prepend(search);
  135. }
  136. titleBar.prepend(createLevelButton());
  137. }
  138. function fixPeopleButton(titleBar) {
  139. if (titleBar.lastChild) {
  140. titleBar.lastChild.addEventListener("click", () => {
  141. if (titleBar.parentElement && titleBar.parentElement.lastChild) {
  142. if (titleBar.parentElement.lastChild.nodeName === "DIV") {
  143. titleBar.parentElement.removeChild(titleBar.parentElement.lastChild);
  144. }
  145. }
  146. });
  147. }
  148. }
  149. function addLevelButtonToTitleBar(header) {
  150. let titleBar = header.querySelector("header div div div.panel ul.icons.d-header-icons");
  151. if (titleBar) {
  152. if (titleBar.querySelector("li#level-button")) {
  153. return;
  154. }
  155. fixSearchButton(titleBar);
  156. fixPeopleButton(titleBar);
  157. } else {
  158. console.warn("query title bar fail.");
  159. }
  160. }
  161. function addHeaderObserver(header) {
  162. if (headerObserver) {
  163. headerObserver.disconnect();
  164. }
  165. headerObserver = new MutationObserver((_) => {
  166. addLevelButtonToTitleBar(header);
  167. });
  168. headerObserver.observe(header, { childList: true });
  169. addLevelButtonToTitleBar(header);
  170. }
  171. function init() {
  172. window.addEventListener("load", () => {
  173. let header = document.querySelector("body section div div.d-header-wrap.drop-down-mode.ember-view");
  174. if (header) {
  175. addHeaderObserver(header);
  176. } else {
  177. let section = document.querySelector("section.ember-application");
  178. if (section) {
  179. let mainObserver = new MutationObserver((_) => {
  180. addHeaderObserver(section.querySelector("body section div div.d-header-wrap.drop-down-mode.ember-view"));
  181. mainObserver.disconnect();
  182. });
  183. mainObserver.observe(section, { childList: true });
  184. }
  185. }
  186. });
  187. window.addEventListener("unload", () => {
  188. if (headerObserver) {
  189. headerObserver.disconnect();
  190. }
  191. });
  192. }
  193. init();
  194. })();
  195.  
  196. })();