Console Importer

通过控制台导入 JS / CSS 库

  1. // ==UserScript==
  2. // @name Console Importer
  3. // @name:en Console Importer
  4. // @description 通过控制台导入 JS / CSS 库
  5. // @description:en Import JavaScript or CSS Library in browser developer tool.
  6. // @author Yiero
  7. // @version 1.2.0
  8. // @match https://*/*
  9. // @license GPL
  10. // @icon https://bbs.tampermonkey.net.cn/favicon.ico
  11. // @run-at document-body
  12. // @grant GM_addElement
  13. // @grant GM_xmlhttpRequest
  14. // @namespace https://github.com/AliubYiero/TamperMonkeyScripts/
  15. // @connect cdnjs.cloudflare.com
  16. // @connect cdn.bootcdn.net
  17. // @connect api.bootcdn.cn
  18. // @connect cdn.jsdelivr.net
  19. // ==/UserScript==
  20. var __defProp = Object.defineProperty;
  21.  
  22. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
  23. enumerable: true,
  24. configurable: true,
  25. writable: true,
  26. value: value
  27. }) : obj[key] = value;
  28.  
  29. var __publicField = (obj, key, value) => {
  30. __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  31. return value;
  32. };
  33.  
  34. class Info {
  35. constructor(projectName) {
  36. __publicField(this, "projectName");
  37. __publicField(this, "header");
  38. this.projectName = projectName;
  39. this.header = `[${projectName}]`;
  40. }
  41. log(...msg) {
  42. (() => {})(...this.contentInfo(...msg));
  43. }
  44. info(...msg) {
  45. console.info(...this.contentInfo(...msg));
  46. }
  47. warn(...msg) {
  48. console.warn(...this.contentInfo(...msg));
  49. }
  50. error(...msg) {
  51. console.error(...this.contentInfo(...msg));
  52. }
  53. group() {
  54. console.group(this.header);
  55. }
  56. groupEnd() {
  57. console.groupEnd();
  58. }
  59. contentInfo(...msg) {
  60. return [ this.header, ...msg ];
  61. }
  62. }
  63.  
  64. function isCSS(url) {
  65. return url.endsWith("css");
  66. }
  67.  
  68. const urlList = new Map;
  69.  
  70. function GMHttpRequest(url, method = "GET", paramOrData, GMXmlHttpRequestConfig = {}) {
  71. if (paramOrData && method === "GET") {
  72. const params = [];
  73. for (const key in paramOrData) {
  74. if (Object.hasOwnProperty.call(paramOrData, key)) {
  75. const value = paramOrData[key];
  76. params.push(`${key}=${JSON.stringify(value)}`);
  77. }
  78. }
  79. url += `?${params.join("?")}`;
  80. } else if (paramOrData && method === "POST") {
  81. GMXmlHttpRequestConfig.data = {
  82. ...paramOrData
  83. };
  84. }
  85. return new Promise(((resolve, reject) => {
  86. const newGMXmlHttpRequestConfig = {
  87. timeout: 2e4,
  88. ...GMXmlHttpRequestConfig,
  89. url: url,
  90. method: method,
  91. onload(response) {
  92. resolve(response);
  93. },
  94. onerror(error) {
  95. reject(error);
  96. }
  97. };
  98. GM_xmlhttpRequest(newGMXmlHttpRequestConfig);
  99. }));
  100. }
  101.  
  102. const api_Bootcdn = async searchLibrary => {
  103. const bootcdnApiDetailDomain = "https://api.bootcdn.cn/libraries/";
  104. const bootcdnApiDomain = "https://cdn.bootcdn.net/ajax/libs/";
  105. const res = await GMHttpRequest(bootcdnApiDetailDomain + searchLibrary);
  106. let link = "";
  107. if (res.status !== 200) {
  108. return Promise.reject("Can not find library from bootcdn...");
  109. } else {
  110. const response = JSON.parse(res.response);
  111. const {filename: filename, version: version} = response[0];
  112. link = `${bootcdnApiDomain}/${searchLibrary}/${version}/${filename}`;
  113. print.log("\u4ece bootcdn \u4e2d\u67e5\u627e\u5230\u5e93: ", link);
  114. return Promise.resolve(link);
  115. }
  116. };
  117.  
  118. async function getBootcdnLibrary(searchLibrary) {
  119. const reSearchLibrary = searchLibrary.endsWith(".js") ? searchLibrary.replace(".js", "") : searchLibrary + ".js";
  120. const searchLibraryList = [ searchLibrary, reSearchLibrary, searchLibrary.toLowerCase(), reSearchLibrary.toLowerCase() ];
  121. for (let i = 0; i < searchLibraryList.length; i++) {
  122. const searchLibrary2 = searchLibraryList[i];
  123. print.warn("\u6b63\u5728\u5c1d\u8bd5\u4ece bootcdn \u4e2d\u83b7\u53d6\u5e93: ", searchLibrary2);
  124. let link = "";
  125. try {
  126. link = await api_Bootcdn(searchLibrary2);
  127. } catch (e) {
  128. print.error("\u83b7\u53d6\u5e93\u5931\u8d25: ", searchLibrary2);
  129. }
  130. if (link.startsWith("http")) {
  131. return link;
  132. }
  133. }
  134. print.error("\u65e0\u6cd5\u4ece bootcdn \u4e2d\u83b7\u53d6\u5230\u5e93: ", searchLibrary);
  135. throw new Error(`Can not found library from bootcdn: ${searchLibrary}`);
  136. }
  137.  
  138. async function getUrl(urlOrLibrary) {
  139. let url;
  140. if (urlOrLibrary.startsWith("https")) {
  141. url = urlOrLibrary;
  142. } else {
  143. url = await getBootcdnLibrary(urlOrLibrary);
  144. }
  145. return url;
  146. }
  147.  
  148. async function installLibrary(urlOrLibrary) {
  149. print.group();
  150. const url = await getUrl(urlOrLibrary);
  151. if (urlList.has(url)) {
  152. print.error(`\u83b7\u53d6\u6570\u636e\u5931\u8d25...\n\u5f53\u524d\u9875\u9762\u4e2d\u5df2\u5b58\u5728\u5e93 [${url}]`);
  153. print.groupEnd();
  154. return;
  155. }
  156. print.info("\u6b63\u5728\u52a0\u8f7d\u6570\u636e...");
  157. GMHttpRequest(url).then((res => {
  158. if (res.status === 404) {
  159. print.error(`\u83b7\u53d6\u6570\u636e\u5931\u8d25...\nError: page not found, request an error url: ${url}`);
  160. print.groupEnd();
  161. return;
  162. } else if (res.status !== 200) {
  163. print.error(`\u83b7\u53d6\u6570\u636e\u5931\u8d25...\nError: ${res.responseText}`);
  164. print.groupEnd();
  165. return;
  166. }
  167. const scriptText = res.responseText;
  168. const isScript = !isCSS(url);
  169. const displayObj = {
  170. tag: isScript ? "script" : "style",
  171. content: isScript ? "\u811a\u672c" : "\u6837\u5f0f\u8868"
  172. };
  173. print.info(`\u6210\u529f\u83b7\u53d6${displayObj.content}, \u6b63\u5728\u8f7d\u5165\u9875\u9762...`);
  174. const element = GM_addElement(document.head, displayObj.tag, {
  175. textContent: scriptText
  176. });
  177. urlList.set(url, element);
  178. print.info(`${displayObj.content}\u8f7d\u5165\u6210\u529f.\n${url}`);
  179. print.groupEnd();
  180. }), (error => {
  181. print.error("\u83b7\u53d6\u6570\u636e\u5931\u8d25...\nError: ", error.error);
  182. print.groupEnd();
  183. }));
  184. }
  185.  
  186. async function uninstallLibrary(url) {
  187. print.group();
  188. const element = urlList.get(await getUrl(url));
  189. if (!element) {
  190. print.warn("\u5f53\u524d\u9875\u9762\u672a\u5b89\u88c5\u5e93: \n", url);
  191. print.groupEnd();
  192. return;
  193. }
  194. element == null ? void 0 : element.remove();
  195. print.info(`\u5f53\u524d\u5e93\u5df2\u5220\u9664: \n`, url);
  196. urlList.delete(url);
  197. print.groupEnd();
  198. }
  199.  
  200. const print = new Info("Console Importer");
  201.  
  202. (() => {
  203. unsafeWindow.$i = installLibrary;
  204. unsafeWindow.$o = getBootcdnLibrary;
  205. unsafeWindow.$ui = uninstallLibrary;
  206. })();