kk-helper

个人开发常用帮助脚本

  1. // ==UserScript==
  2. // @name kk-helper
  3. // @namespace https://gf.qytechs.cn/zh-CN/users/1167332-stephenykk
  4. // @homepage https://gf.qytechs.cn/zh-CN/scripts/474672-kk-helper
  5. // @version 3.0.0
  6. // @description 个人开发常用帮助脚本
  7. // @author #stephenykk
  8. // @match https://juejin.cn/post/*
  9. // @match https://blog.csdn.net/*/article/details/*
  10. // @match https://www.jianshu.com/p/*
  11. // @match https://segmentfault.com/a/*
  12. // @match https://mp.weixin.qq.com/s*
  13. // @match https://zhuanlan.zhihu.com/p/*
  14. // @match https://sspai.com/post/*
  15. // @match *://www.news.cn/*/**/*.htm*
  16. // @match *://*.people.com.cn/*/**/*.htm*
  17. // @icon https://res.wx.qq.com/a/fed_upload/9300e7ac-cec5-4454-b75c-f92260dd5b47/logo-mp.ico
  18. // @grant none
  19. // @license MIT
  20. // ==/UserScript==
  21.  
  22. (function () {
  23. "use strict";
  24. function log(...args) {
  25. console.log("[KKCopy]", ...args);
  26. }
  27.  
  28. const autoClick = (ele, callback, seconds = 2) => {
  29. console.log("try auto click ele:", ele);
  30. ele.click();
  31. callback && setTimeout(callback, seconds * 1000);
  32. };
  33.  
  34. function toast(msg) {
  35. const toastEle = document.createElement("div");
  36. toastEle.style = `
  37. position: fixed;
  38. top: 30%;
  39. left: 50%;
  40. transform: translate(-50%, -50%);
  41. background: rgba(0, 0, 0, 0.7);
  42. color: white;
  43. padding: 15px 30px;
  44. border-radius: 5px;
  45. z-index: 1000000;
  46. font-size: 15px;
  47. line-height: 1.5;
  48. `;
  49. toastEle.innerText = msg;
  50. document.body.appendChild(toastEle);
  51. setTimeout(() => {
  52. document.body.removeChild(toastEle);
  53. }, 2000);
  54. }
  55.  
  56. const btnStyle = `
  57. opacity: 0.7;
  58. font-size: 15px;
  59. border: 0;
  60. background: brown;
  61. color: white;
  62. padding: 8px 16px;
  63. border-radius: 5px;
  64. cursor: pointer;
  65. margin: 0 20px;
  66. `;
  67.  
  68. function createBtn(text, listener, style = "") {
  69. let btnsWrap = $("#myBtnsWrap");
  70. if (!btnsWrap) {
  71. btnsWrap = document.createElement("div");
  72. btnsWrap.id = "myBtnsWrap";
  73. btnsWrap.style =
  74. "position: fixed; left: 50%; top: 10px; z-index: 10000; transform: translateX(-50%);";
  75. document.body.appendChild(btnsWrap);
  76. }
  77. // if (this.mybtn) return;
  78. const btn = document.createElement("button");
  79. btn.textContent = text || "Submit";
  80. btn.className = "mybtn";
  81. btn.setAttribute("data-txt", text);
  82. btn.style = btnStyle + style;
  83. btnsWrap.appendChild(btn);
  84. btn.addEventListener("click", listener);
  85. console.log("createBtn: btn=", btn);
  86. // this.mybtn = btn;
  87. return btn;
  88. }
  89.  
  90. function getCopyMethod() {
  91. let input = document.querySelector("#myInputEle");
  92. if (input) {
  93. return input.copyOf;
  94. }
  95.  
  96. const inpEle = document.createElement("input");
  97. inpEle.type = "text";
  98. document.body.insertBefore(inpEle, null);
  99. inpEle.style = "position: fixed; top: -100px; right: 0; z-index: 10000;";
  100. inpEle.setAttribute("id", "myInputEle");
  101. input = inpEle;
  102.  
  103. const doCopy = function (text) {
  104. input.value = text;
  105. input.select();
  106. input.setSelectionRange(0, input.value.length);
  107. document.execCommand("copy");
  108. toast("copy ok");
  109. log("copy done");
  110. };
  111.  
  112. input.copyOf = doCopy;
  113.  
  114. return input.copyOf;
  115. }
  116.  
  117. function $(selector) {
  118. return document.querySelector(selector);
  119. }
  120.  
  121. class OriginLinkCopyAction {
  122. start() {
  123. // 复制原文地址按钮
  124. this.btn = createBtn("原文地址", () => {
  125. const copy = getCopyMethod();
  126. copy(`> 原文地址: [${document.title}](${location.href})`);
  127. });
  128. }
  129. }
  130.  
  131. // eslint-disable-next-line
  132. const linkCopyAction = new OriginLinkCopyAction();
  133. linkCopyAction.start();
  134.  
  135. class BlogTitleCopyAction {
  136. start() {
  137. // 复制原文地址按钮
  138. this.btn = createBtn(
  139. "文章标题",
  140. () => {
  141. const copy = getCopyMethod();
  142. copy(document.title);
  143. },
  144. "right: 300px"
  145. );
  146. }
  147. }
  148.  
  149. const titleCopyAction = new BlogTitleCopyAction();
  150. titleCopyAction.start();
  151.  
  152. // 表单填写
  153. class FormFiller {
  154. constructor(enableUrl, values, btn) {
  155. this.url = enableUrl;
  156. this.values = values;
  157. this.btn = btn;
  158. }
  159.  
  160. element(selector) {
  161. return $(selector);
  162. }
  163.  
  164. fill() {
  165. const inputSelectors = Object.keys(this.values);
  166. const inputValues = Object.values(this.values);
  167. inputSelectors.forEach((inpSelctor, i) => {
  168. const input = this.element(inpSelctor);
  169. if (input) {
  170. input.value = inputValues[i];
  171. } else {
  172. console.log("not found element for", inpSelctor);
  173. }
  174. });
  175. }
  176.  
  177. submit() {
  178. if (this.btn.selector) {
  179. const submitBtn = this.element(this.btn.selector);
  180. submitBtn?.click();
  181. return;
  182. }
  183.  
  184. console.log("not found submitBtn cancel", this.btn); // debug only
  185. }
  186.  
  187. createBtn() {
  188. // if (this.mybtn) return;
  189. const btn = document.createElement("button");
  190. btn.textContent = this.btn.text || "Submit";
  191. btn.className = "mybtn";
  192. btn.style = btnStyle;
  193. document.body.appendChild(btn);
  194. // this.mybtn = btn;
  195. return btn;
  196. }
  197.  
  198. start() {
  199. if (location.href.includes(this.url) === false) return;
  200.  
  201. this.mybtn = this.createBtn();
  202. // click mybtn, fill data to input box, and trigger submit button click method
  203. this.mybtn.addEventListener("click", () => {
  204. this.fill();
  205. this.submit();
  206. });
  207. }
  208. }
  209. })();
  210.  
  211. (function () {
  212. function clearStorageAndCookie(isrefresh = true) {
  213. [sessionStorage, localStorage].forEach((storage) => storage.clear());
  214. clearCookies();
  215. console.log(document.cookie, "done!!");
  216. isrefresh && setTimeout(location.reload.bind(location), 1000);
  217. }
  218.  
  219. function pick(data, keys) {
  220. return keys.reduce((ret, key) => {
  221. ret[key] = data[key];
  222. return ret;
  223. }, {});
  224. }
  225.  
  226. function localCacheEntries(data) {
  227. Object.keys(data).forEach((key) => {
  228. localStorage[key] = data[key];
  229. });
  230.  
  231. console.log("done", localStorage);
  232. }
  233.  
  234. function getCookies() {
  235. return document.cookie.match(/[\w-]+(?=\=[^;]+)/g) || [];
  236. }
  237.  
  238. function clearCookies() {
  239. getCookies().forEach((cname) => {
  240. delCookie(cname);
  241. });
  242. }
  243.  
  244. function setCookie(cname, cvalue, exdays) {
  245. const d = new Date();
  246. d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
  247. const expires = "; Expires=" + d.toUTCString();
  248. // document.cookie = cname + "=" + cvalue + expires + "; Path=/";
  249. document.cookie = cname + "=" + cvalue + expires;
  250. }
  251.  
  252. function delCookie(cname) {
  253. console.log("del cookie:", cname);
  254. setCookie(cname, "", -1);
  255. }
  256.  
  257. function copy(str) {
  258. const el = document.createElement("textarea");
  259. el.value = str;
  260. el.setAttribute("readonly", "");
  261. el.style.position = "absolute";
  262. el.style.left = "-9999px";
  263. document.body.appendChild(el);
  264. el.select();
  265. document.execCommand("copy");
  266. document.body.removeChild(el);
  267. }
  268.  
  269. function toUnicode(str) {
  270. const ls = str.split("");
  271. const result = ls
  272. .map((c) => {
  273. if (/\w/.test(c)) return c;
  274.  
  275. return "\\u" + c.charCodeAt(0).toString(16).toUpperCase();
  276. })
  277. .join("");
  278.  
  279. copy(result);
  280. console.log("copy done");
  281. return result;
  282. }
  283.  
  284. function isPlainObject(val) {
  285. return Object.prototype.toString.call(val).slice(8, -1) === "Object";
  286. }
  287.  
  288. function getTableTypeDefines(vm) {
  289. const { tableData, schema } = vm.props ?? {};
  290. if (!tableData) {
  291. console.warn("not tableData found:", vm.props);
  292. return;
  293. }
  294.  
  295. return getTypeDefines(tableData[0], schema);
  296. }
  297.  
  298. function getTypeDefines(obj = {}, schema = false, level = 10) {
  299. // if (Array.isArray(obj)) {
  300. // if (obj.length === 0) {
  301. // return 'Array<any>'
  302. // }
  303. // return `Array<${getTypeDefines(obj[0], schema, level - 1)}>`
  304. // }
  305. if (Array.isArray(obj)) {
  306. obj = obj[0];
  307. }
  308.  
  309. const getPrimativeType = (key, val) => {
  310. let type = typeof val;
  311. let text = "";
  312.  
  313. if (!schema) {
  314. return { type, text };
  315. }
  316.  
  317. const props = schema.properties ?? {};
  318. if (props[key]) {
  319. type = props[key].type;
  320. text = props[key].title;
  321. }
  322.  
  323. return { type, text };
  324. };
  325. let ret = "{\n";
  326. Object.keys(obj).forEach((key) => {
  327. if (key.startsWith("_")) return;
  328. const val = obj[key];
  329. const isPrimative = !isPlainObject(val) && !Array.isArray(val);
  330. let title = "";
  331. let valType;
  332. if (isPrimative) {
  333. const { type, text } = getPrimativeType(key, val);
  334. valType = type;
  335. title = text;
  336. } else {
  337. valType = getTypeDefines(val, schema);
  338. }
  339.  
  340. const keyDefine = `${key}: ${valType};${title ? " // " + title : ""}\n`;
  341. ret += keyDefine;
  342. });
  343. ret += "\n}";
  344.  
  345. copy(ret);
  346. console.log("copy done!");
  347. return ret;
  348. }
  349.  
  350. window.my = {
  351. getTableTypeDefines,
  352.  
  353. toUnicode,
  354. pick,
  355. copy,
  356.  
  357. getCookies,
  358. setCookie,
  359. delCookie,
  360. clearCookies,
  361.  
  362. localCacheEntries,
  363. clearStorageAndCookie,
  364. };
  365. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址