├── meta
├── blank.ts
└── debug.ts
├── packages
├── site-director
│ ├── src
│ │ ├── style.css
│ │ ├── utils.ts
│ │ ├── modules
│ │ │ ├── qq-mail.ts
│ │ │ ├── juejin.ts
│ │ │ ├── jianshu.ts
│ │ │ ├── csdn.ts
│ │ │ ├── zhihu.ts
│ │ │ └── google.ts
│ │ ├── index.ts
│ │ └── websites.ts
│ ├── README.md
│ ├── package.json
│ └── meta.json
├── force-copy
│ ├── .gitignore
│ ├── src
│ │ ├── utils
│ │ │ ├── is.ts
│ │ │ ├── global.ts
│ │ │ ├── constant.ts
│ │ │ ├── reload.ts
│ │ │ ├── types.ts
│ │ │ └── logger.ts
│ │ ├── bridge
│ │ │ ├── content-worker
│ │ │ │ ├── constant.ts
│ │ │ │ ├── request.ts
│ │ │ │ └── index.ts
│ │ │ ├── popup-content
│ │ │ │ ├── constant.ts
│ │ │ │ ├── response.ts
│ │ │ │ ├── request.ts
│ │ │ │ └── index.ts
│ │ │ ├── popup-worker
│ │ │ │ ├── constant.ts
│ │ │ │ ├── request.ts
│ │ │ │ └── index.ts
│ │ │ ├── worker-content
│ │ │ │ ├── constant.ts
│ │ │ │ ├── request.ts
│ │ │ │ └── index.ts
│ │ │ └── content-inject
│ │ │ │ ├── constant.ts
│ │ │ │ ├── request.ts
│ │ │ │ └── index.ts
│ │ ├── inject
│ │ │ ├── types
│ │ │ │ ├── state.ts
│ │ │ │ ├── global.d.ts
│ │ │ │ └── website.ts
│ │ │ ├── modules
│ │ │ │ ├── index.ts
│ │ │ │ ├── basic.ts
│ │ │ │ ├── qq-ppt.ts
│ │ │ │ ├── docin.ts
│ │ │ │ ├── zhihu.ts
│ │ │ │ ├── wenku.ts
│ │ │ │ ├── qq-doc.ts
│ │ │ │ └── doc88.ts
│ │ │ ├── utils
│ │ │ │ ├── delay.ts
│ │ │ │ ├── styles.ts
│ │ │ │ ├── bus.ts
│ │ │ │ └── events.ts
│ │ │ ├── index.ts
│ │ │ └── channel
│ │ │ │ └── content.ts
│ │ ├── popup
│ │ │ ├── components
│ │ │ │ ├── header
│ │ │ │ │ ├── index.module.scss
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── console
│ │ │ │ │ ├── index.module.scss
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── tools
│ │ │ │ │ ├── index.module.scss
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── app
│ │ │ │ │ ├── index.module.scss
│ │ │ │ │ └── index.tsx
│ │ │ │ └── footer
│ │ │ │ │ ├── index.module.scss
│ │ │ │ │ └── index.tsx
│ │ │ ├── i18n
│ │ │ │ ├── zh.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── en.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.tsx
│ │ │ ├── hooks
│ │ │ │ └── use-memoized-fn.ts
│ │ │ └── utils
│ │ │ │ └── badge.ts
│ │ ├── types
│ │ │ └── global.d.ts
│ │ ├── worker
│ │ │ ├── index.ts
│ │ │ ├── utils
│ │ │ │ └── constant.ts
│ │ │ ├── channel
│ │ │ │ └── content.ts
│ │ │ └── runtime
│ │ │ │ ├── initialize.ts
│ │ │ │ └── script.ts
│ │ ├── content
│ │ │ ├── index.ts
│ │ │ ├── runtime
│ │ │ │ ├── initialize.ts
│ │ │ │ └── script.ts
│ │ │ └── channel
│ │ │ │ └── popup.ts
│ │ └── manifest
│ │ │ ├── types.ts
│ │ │ └── index.ts
│ ├── public
│ │ ├── locales
│ │ │ ├── en
│ │ │ │ └── messages.json
│ │ │ └── zh_cn
│ │ │ │ └── messages.json
│ │ ├── misc
│ │ │ ├── brick.png
│ │ │ ├── poster.png
│ │ │ └── favicon.dark.png
│ │ ├── static
│ │ │ ├── favicon.png
│ │ │ └── favicon.128.png
│ │ └── popup.html
│ ├── tsconfig.json
│ ├── script
│ │ ├── if-def
│ │ │ ├── if-def.code-snippets
│ │ │ ├── package.json
│ │ │ └── index.js
│ │ ├── reload
│ │ │ └── index.js
│ │ ├── utils
│ │ │ └── node.js
│ │ ├── manifest
│ │ │ └── index.js
│ │ ├── files
│ │ │ └── index.js
│ │ └── wrapper
│ │ │ └── index.js
│ ├── README.md
│ ├── package.json
│ └── rspack.config.js
├── expansion
│ ├── README.md
│ ├── package.json
│ └── expansion.user.js
├── water-mark
│ ├── README.md
│ ├── src
│ │ ├── types
│ │ │ ├── website.ts
│ │ │ └── global.d.ts
│ │ ├── index.ts
│ │ ├── utils
│ │ │ ├── constant.ts
│ │ │ ├── styles.ts
│ │ │ └── dom.ts
│ │ └── modules
│ │ │ └── basic.ts
│ ├── tsconfig.json
│ ├── package.json
│ └── meta.json
├── captcha
│ ├── README.md
│ ├── package.json
│ └── captcha.user.js
├── completion
│ ├── README.md
│ ├── package.json
│ └── completion.user.js
├── copy
│ ├── tsconfig.json
│ ├── src
│ │ ├── styles
│ │ │ ├── style.css
│ │ │ └── app.css
│ │ ├── modules
│ │ │ ├── 17k.ts
│ │ │ ├── bilibili.ts
│ │ │ ├── uemeds.ts
│ │ │ ├── aiyuke.ts
│ │ │ ├── csdn.ts
│ │ │ ├── diyifanwen.ts
│ │ │ ├── utaten.ts
│ │ │ ├── xiaohongshu.ts
│ │ │ ├── mbalib.ts
│ │ │ ├── cnitpm.ts
│ │ │ ├── cnki.ts
│ │ │ ├── mihoyo.ts
│ │ │ ├── qidian.ts
│ │ │ ├── qqbook.ts
│ │ │ ├── ciweimao.ts
│ │ │ ├── sf.ts
│ │ │ ├── wk.ts
│ │ │ ├── leetcode.ts
│ │ │ ├── common-e.ts
│ │ │ ├── edu30.ts
│ │ │ ├── common-p.ts
│ │ │ ├── zongheng.ts
│ │ │ ├── youdao.ts
│ │ │ ├── kdocs.ts
│ │ │ ├── docin.ts
│ │ │ ├── boke112.ts
│ │ │ ├── doc88.ts
│ │ │ ├── common.ts
│ │ │ ├── qq-slider.ts
│ │ │ ├── zhihu.ts
│ │ │ └── docqq.ts
│ │ ├── types
│ │ │ └── global.d.ts
│ │ ├── constant
│ │ │ └── event.ts
│ │ ├── utils
│ │ │ ├── is.ts
│ │ │ ├── dom.ts
│ │ │ ├── copy.ts
│ │ │ ├── instance.ts
│ │ │ └── event.ts
│ │ ├── index.ts
│ │ ├── init.ts
│ │ ├── deploy.ts
│ │ └── websites.ts
│ ├── package.json
│ ├── meta.json
│ └── README.md
└── copy-currency
│ ├── src
│ ├── global.d.ts
│ ├── utils.ts
│ ├── index.css
│ ├── register.ts
│ └── index.ts
│ ├── package.json
│ ├── README.md
│ └── meta.json
├── pnpm-workspace.yaml
├── .npmrc
├── .vscode
└── settings.json
├── .editorconfig
├── publish-scripts.sh
├── .gitignore
├── .prettierrc.js
├── .github
├── ISSUE_TEMPLATE.md
└── workflows
│ └── deploy-scripts.yml
├── tsconfig.json
├── LICENSE
├── .eslintrc.js
├── package.json
├── rollup.config.js
└── README.md
/meta/blank.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
--------------------------------------------------------------------------------
/packages/site-director/src/style.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "packages/*"
--------------------------------------------------------------------------------
/packages/force-copy/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | build-gecko
3 |
--------------------------------------------------------------------------------
/packages/expansion/README.md:
--------------------------------------------------------------------------------
1 | # 自动展开阅读全文
2 |
3 | 展开阅读全文,用于`CSDN`、知乎。
4 |
--------------------------------------------------------------------------------
/packages/water-mark/README.md:
--------------------------------------------------------------------------------
1 | # 移除页面水印
2 |
3 | 独立适配模式,移除常见网页的水印。
4 |
--------------------------------------------------------------------------------
/packages/force-copy/src/utils/is.ts:
--------------------------------------------------------------------------------
1 | export const isInIframe = self !== top;
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmmirror.com/
2 | # strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "rspack"
4 | ]
5 | }
--------------------------------------------------------------------------------
/packages/captcha/README.md:
--------------------------------------------------------------------------------
1 | # 强智教务系统验证码识别
2 |
3 | 自动填写强智的验证码,请自行处理`@match`到需要匹配的网站。
4 |
--------------------------------------------------------------------------------
/packages/completion/README.md:
--------------------------------------------------------------------------------
1 | # 阿里矢量图标库添加`HTTP`按钮
2 |
3 | 阿里矢量图标库添加`HTTP`按钮,简化手动填写。
4 |
--------------------------------------------------------------------------------
/packages/site-director/README.md:
--------------------------------------------------------------------------------
1 | # 跳转链接直达
2 |
3 | 跳转链接直达,自动跳转链接的中间页面,用于谷歌、知乎、`CSDN`、简书。
4 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-worker/constant.ts:
--------------------------------------------------------------------------------
1 | export const MARK = "CW" as const;
2 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-content/constant.ts:
--------------------------------------------------------------------------------
1 | export const MARK = "PC" as const;
2 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-worker/constant.ts:
--------------------------------------------------------------------------------
1 | export const MARK = "PW" as const;
2 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/worker-content/constant.ts:
--------------------------------------------------------------------------------
1 | export const MARK = "WC" as const;
2 |
--------------------------------------------------------------------------------
/packages/force-copy/public/locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "Force Copy"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/force-copy/public/locales/zh_cn/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "Force Copy"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/water-mark/src/types/website.ts:
--------------------------------------------------------------------------------
1 | export type Website = {
2 | regexp: RegExp;
3 | init: () => void;
4 | };
5 |
--------------------------------------------------------------------------------
/packages/copy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": ["./src/**/*.ts", "./src/**/*.tsx"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/water-mark/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": ["./src/**/*.ts", "./src/**/*.tsx"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/force-copy/public/misc/brick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindRunnerMax/TKScript/HEAD/packages/force-copy/public/misc/brick.png
--------------------------------------------------------------------------------
/packages/force-copy/public/misc/poster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindRunnerMax/TKScript/HEAD/packages/force-copy/public/misc/poster.png
--------------------------------------------------------------------------------
/packages/force-copy/public/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindRunnerMax/TKScript/HEAD/packages/force-copy/public/static/favicon.png
--------------------------------------------------------------------------------
/packages/force-copy/src/inject/types/state.ts:
--------------------------------------------------------------------------------
1 | export type State = {
2 | COPY: boolean;
3 | KEYBOARD: boolean;
4 | CONTEXT_MENU: boolean;
5 | };
6 |
--------------------------------------------------------------------------------
/packages/force-copy/public/misc/favicon.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindRunnerMax/TKScript/HEAD/packages/force-copy/public/misc/favicon.dark.png
--------------------------------------------------------------------------------
/packages/force-copy/public/static/favicon.128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindRunnerMax/TKScript/HEAD/packages/force-copy/public/static/favicon.128.png
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-inject/constant.ts:
--------------------------------------------------------------------------------
1 | export const MARK = "CI" as const;
2 | export const EVENT_TYPE = process.env.EVENT_TYPE || "EVENT_TYPE_CI";
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/packages/force-copy/src/utils/global.ts:
--------------------------------------------------------------------------------
1 | let env = chrome;
2 |
3 | // #IFDEF GECKO
4 | if (typeof browser !== "undefined") {
5 | env = browser;
6 | }
7 | // #ENDIF
8 |
9 | export const cross = env;
10 |
--------------------------------------------------------------------------------
/packages/force-copy/src/inject/types/global.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | declare interface Window {
3 | pad?: any;
4 | wrappedJSObject?: any;
5 | SpreadsheetApp?: any;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/water-mark/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | declare const unsafeWindow = any;
2 |
3 | declare module "*.css" {
4 | const content: string;
5 | export default content;
6 | }
7 |
8 | declare const GM_addStyle: (css: string) => void;
9 |
--------------------------------------------------------------------------------
/packages/force-copy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "paths": {
5 | "@/*": ["./src/*"]
6 | }
7 | },
8 | "include": ["./src/**/*.ts", "./src/**/*.tsx"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/copy-currency/src/global.d.ts:
--------------------------------------------------------------------------------
1 | declare const unsafeWindow = any;
2 |
3 | declare function GM_registerMenuCommand(name: string, fn: () => void, index?: string): number;
4 | declare function GM_unregisterMenuCommand(id: number): void;
5 |
--------------------------------------------------------------------------------
/packages/captcha/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "captcha",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/completion/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "completion",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/expansion/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expansion",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/site-director/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "site-director",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/water-mark/src/index.ts:
--------------------------------------------------------------------------------
1 | import { basic } from "./modules/basic";
2 | import type { Website } from "./types/website";
3 |
4 | const websites: Website[] = [basic];
5 | const web = websites.find(item => item.regexp.test(location.href));
6 | web && web.init();
7 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/header/index.module.scss:
--------------------------------------------------------------------------------
1 | .captain {
2 | align-items: center;
3 | display: flex;
4 |
5 | img {
6 | height: 20px;
7 | margin-right: 5px;
8 | width: 20px;
9 | }
10 |
11 | padding-bottom: 3px;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/copy/src/styles/style.css:
--------------------------------------------------------------------------------
1 | div[id^=reader-helper],
2 | #sfModal,
3 | #select-tooltip{
4 | display: none !important;
5 | }
6 |
7 | .modal-open{
8 | overflow: auto !important;
9 | }
10 |
11 | ._sf_adjust_body{
12 | padding-right: 0 !important;
13 | }
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/console/index.module.scss:
--------------------------------------------------------------------------------
1 | .console {
2 | position: relative;
3 | > div {
4 | margin: 10px 5px;
5 | display: flex;
6 | align-items: center;
7 | }
8 | }
9 |
10 | .switch {
11 | display: flex;
12 | justify-content: center;
13 | }
14 |
--------------------------------------------------------------------------------
/packages/force-copy/script/if-def/if-def.code-snippets:
--------------------------------------------------------------------------------
1 | {
2 | "if-def-code-snippet": {
3 | "scope": "javascript,typescript,javascriptreact,typescriptreact",
4 | "prefix": "#IFDEF",
5 | "body": ["// #IFDEF ${1:PLATFORM}", "$0", "// #ENDIF"],
6 | "description": "IFDEF --- ENDIF"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/publish-scripts.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ex
3 |
4 | npx rollup -c
5 | cp ./packages/expansion/expansion.user.js ./dist/expansion.user.js
6 | cp ./packages/captcha/captcha.user.js ./dist/captcha.user.js
7 | cp ./packages/completion/completion.user.js ./dist/completion.user.js
8 | cp ./README.md ./dist/README.md
9 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/tools/index.module.scss:
--------------------------------------------------------------------------------
1 | $box-shadow: 0 0 4px var(--color-border-2);
2 |
3 | .container {
4 | background-color: var(--color-bg-4);
5 | padding: 10px;
6 |
7 | border: 1px solid var(--color-border-2);
8 | border-radius: 4px;
9 | box-shadow: $box-shadow;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/packages/site-director/src/utils.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | directByBlockEvent: function (event: Event): void {
3 | event.stopPropagation();
4 | event.preventDefault();
5 | },
6 | directByCapture: function (el: Element): void {
7 | el.addEventListener("click", e => this.directByBlockEvent(e));
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/packages/copy-currency/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "copy-currency",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | },
10 | "sideEffects": false,
11 | "files": [
12 | "src"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/17k.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("17k"),
6 | init: () => {
7 | utils.hideButton();
8 | utils.enableOnCopy(".readAreaBox .p");
9 | },
10 | };
11 |
12 | export default website;
13 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/bilibili.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("bilibili"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnCopyByCapture();
9 | },
10 | };
11 |
12 | export default website;
13 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/uemeds.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp(".+www.uemeds.cn/.+"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | },
10 | };
11 |
12 | export default website;
13 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/aiyuke.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp(".+aiyuke.com/news/.+"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | },
10 | };
11 |
12 | export default website;
13 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/csdn.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /csdn/,
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnCopyByCapture();
9 | utils.enableUserSelectByCSS();
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/force-copy/src/utils/constant.ts:
--------------------------------------------------------------------------------
1 | export const COPY_TYPE = "__COPY__";
2 | export const KEYBOARD_TYPE = "__KEYBOARD_TYPE__";
3 | export const CONTEXT_MENU_TYPE = "__CONTEXT_MENU_TYPE__";
4 | export const URL_MATCH = ["https://*/*", "http://*/*", "file://*/*"];
5 |
6 | export type ActionType = typeof COPY_TYPE | typeof KEYBOARD_TYPE | typeof CONTEXT_MENU_TYPE;
7 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/diyifanwen.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /diyifanwen/,
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnCopyByCapture();
9 | utils.enableOnKeyDownByCapture();
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/utaten.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("utaten"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | utils.enableOnSelectStartByCapture();
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/app/index.module.scss:
--------------------------------------------------------------------------------
1 | body {
2 | user-select: none;
3 | background-color: var(--color-bg-3);
4 | }
5 |
6 | .container {
7 | padding: 10px;
8 | width: 270px;
9 | color: var(--color-text-1);
10 | }
11 |
12 | .hr {
13 | margin: 5px 0;
14 | height: 1px;
15 | background-color: var(--color-border-3);
16 | width: 100%;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/xiaohongshu.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("xiaohongshu"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | utils.enableOnKeyDownByCapture();
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/qq-mail.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /mail\.qq/,
5 | init: function () {
6 | const result = new URL(location.href).searchParams.get("gourl");
7 | if (result) {
8 | location.href = decodeURIComponent(result);
9 | }
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/juejin.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /link\.juejin/,
5 | init: function () {
6 | const result = new URL(location.href).searchParams.get("target");
7 | if (result) {
8 | location.href = decodeURIComponent(result);
9 | }
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/mbalib.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /mbalib/,
6 | init: function () {
7 | window.onload = () => {
8 | utils.removeAttributes("fullScreenContainer", ["oncopy", "oncontextmenu", "onselectstart"]);
9 | };
10 | },
11 | };
12 |
13 | export default website;
14 |
--------------------------------------------------------------------------------
/packages/force-copy/public/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | POPUP
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/packages/copy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "copy",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | },
10 | "scripts": {
11 | "lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
12 | },
13 | "sideEffects": false,
14 | "files": [
15 | "src"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/cnitpm.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /cnitpm/,
6 | init: function () {
7 | utils.hideButton();
8 | window.onload = () => {
9 | utils.removeAttributes("body", ["oncopy", "oncontextmenu", "onselectstart"]);
10 | };
11 | },
12 | };
13 |
14 | export default website;
15 |
--------------------------------------------------------------------------------
/packages/copy/src/styles/app.css:
--------------------------------------------------------------------------------
1 | .__copy-button {
2 | width: 60px;
3 | height: 30px;
4 | background: #4C98F7;
5 | color: #fff;
6 | position: absolute;
7 | z-index: -1000;
8 | opacity: 0;
9 | display: flex;
10 | justify-content: center;
11 | align-items: center;
12 | border-radius: 3px;
13 | font-size: 13px;
14 | cursor: pointer;
15 | transition: opacity 0.3s;
16 | }
--------------------------------------------------------------------------------
/packages/site-director/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "./websites";
2 | import websites from "./websites";
3 |
4 | ((): void => {
5 | const mather = (regex: RegExp, website: Website) => {
6 | if (regex.test(window.location.href)) {
7 | website.init();
8 | return true;
9 | }
10 | return false;
11 | };
12 | websites.some(website => mather(website.regexp, website));
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/cnki.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("cnki"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnContextMenuByCapture();
9 | utils.enableOnKeyDownByCapture();
10 | utils.enableOnCopyByCapture();
11 | },
12 | };
13 |
14 | export default website;
15 |
--------------------------------------------------------------------------------
/packages/water-mark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "water-mark",
3 | "version": "1.0.0",
4 | "author": "Czy",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/WindrunnerMax/TKScript"
9 | },
10 | "scripts": {
11 | "lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
12 | },
13 | "sideEffects": false,
14 | "files": [
15 | "src"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # base
2 | backup
3 | node_modules
4 | *.log
5 | .DS_Store
6 | .idea
7 | *.zip
8 |
9 | # dependencies
10 | node_modules
11 | .pnp
12 | .pnp.js
13 |
14 | # testing
15 | coverage
16 |
17 | # production
18 | build
19 | dist
20 |
21 | # misc
22 | .DS_Store
23 | .env.local
24 | .env.development.local
25 | .env.test.local
26 | .env.production.local
27 |
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/mihoyo.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp(".+bbs.mihoyo.com/.+"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnCopyByCapture();
9 | utils.enableOnSelectStartByCapture();
10 | utils.enableUserSelectByCSS();
11 | },
12 | };
13 |
14 | export default website;
15 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/qidian.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("qidian"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | utils.enableOnCopy(".main-read-container");
10 | utils.enableOnContextMenu(".main-read-container");
11 | },
12 | };
13 |
14 | export default website;
15 |
--------------------------------------------------------------------------------
/packages/force-copy/src/inject/modules/index.ts:
--------------------------------------------------------------------------------
1 | import type { WebSite } from "../types/website";
2 | import { Basic } from "./basic";
3 | import { Doc88 } from "./doc88";
4 | import { DocIn } from "./docin";
5 | import { QQDoc } from "./qq-doc";
6 | import { QQPpt } from "./qq-ppt";
7 | import { Wenku } from "./wenku";
8 | import { Zhihu } from "./zhihu";
9 |
10 | export const websites: WebSite[] = [Wenku, Doc88, QQDoc, DocIn, Zhihu, QQPpt, Basic];
11 |
--------------------------------------------------------------------------------
/packages/copy-currency/README.md:
--------------------------------------------------------------------------------
1 | # 文本选中复制-通用版
2 | 文本选中复制通用版本,适用于大多数网站。
3 | 由于会匹配所有网站,为了减少对于正常网站的干扰,在打开网站之后,**需要自行在网站左下角找到淡蓝色块,鼠标悬浮之后,点击启动 解除复制限制 按钮**。
4 | 某度文库、道客某某等网站需要特殊处理,不能通用处理,请移步 文本选中复制 脚本。
5 |
6 | 
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/qqbook.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("book\\.qq"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableOnCopy("body");
9 | utils.enableUserSelectByCSS();
10 | utils.enableOnContextMenu("body");
11 | utils.enableOnSelectStart("body");
12 | },
13 | };
14 |
15 | export default website;
16 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/jianshu.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /jianshu/,
5 | init: function () {
6 | const result = /.*jianshu.com\/go-wild.*url=(.*)/.exec(location.href);
7 | if (result) {
8 | const url = decodeURIComponent(result[1]);
9 | if (url) {
10 | location.href = url;
11 | }
12 | }
13 | },
14 | };
15 |
16 | export default website;
17 |
--------------------------------------------------------------------------------
/meta/debug.ts:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name DEBUG
3 | // @description DEBUG MODE
4 | // @namespace https://github.com/WindrunnerMax/TKScript
5 | // @version 1.0.0
6 | // @author Czy
7 | // @match http://*/*
8 | // @match https://*/*
9 | // @license GPL License
10 | // @run-at document-end
11 | // @grant GM_notification
12 | // @require file:///Users/czy/Project/TKScript/dist/copy-currency.user.js
13 | // ==/UserScript==
14 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/i18n/zh.ts:
--------------------------------------------------------------------------------
1 | import { en } from "./en";
2 | import type { DefaultI18nConfig } from "./types";
3 |
4 | export const zh: DefaultI18nConfig = {
5 | Title: "Force Copy",
6 | Captain: {
7 | Modules: "模块",
8 | Start: "启动",
9 | Once: "仅本次",
10 | },
11 | Operation: {
12 | Copy: "解除复制限制",
13 | Keyboard: "解除键盘限制",
14 | ContextMenu: "解除右键限制",
15 | },
16 | Information: en.Information,
17 | Tools: en.Tools,
18 | };
19 |
--------------------------------------------------------------------------------
/packages/force-copy/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.scss" {
2 | const content: Record;
3 | export default content;
4 | }
5 |
6 | declare const __DEV__: boolean;
7 | declare const browser: typeof chrome | undefined;
8 |
9 | declare namespace NodeJS {
10 | interface ProcessEnv {
11 | NODE_ENV: "development" | "production";
12 | PLATFORM: "chromium" | "gecko";
13 | EVENT_TYPE: string;
14 | INJECT_FILE: string;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/ciweimao.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("ciweimao"),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | utils.enableOnCopy("#J_BookCnt");
10 | utils.enableOnContextMenu("body");
11 | utils.enableOnSelectStart("#J_BookCnt");
12 | },
13 | };
14 |
15 | export default website;
16 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/sf.ts:
--------------------------------------------------------------------------------
1 | import dom from "../utils/dom";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /.*segmentfault\.com\/.+/,
6 | init: function () {
7 | const body = dom.query("body");
8 | if (body) {
9 | body.classList.add("_sf_adjust_body");
10 | body.onclick = () => {
11 | body.style.paddingRight = "0";
12 | };
13 | }
14 | },
15 | };
16 |
17 | export default website;
18 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/csdn.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /csdn/,
5 | init: function () {
6 | const result = /.*link.csdn.net\/\?target=(.*)/.exec(location.href);
7 | if (result) {
8 | const url = decodeURIComponent(result[1]);
9 | if (url) {
10 | console.log(url);
11 | location.href = url;
12 | }
13 | }
14 | },
15 | };
16 |
17 | export default website;
18 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/wk.ts:
--------------------------------------------------------------------------------
1 | import dom from "../utils/dom";
2 | import utils from "../utils/event";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | regexp: /.*wk\.baidu\.com\/view\/.+/,
7 | init: function () {
8 | utils.hideButton();
9 | utils.enableOnSelectStartByCapture();
10 | window.onload = () => {
11 | dom.attr(".sf-edu-wenku-vw-container", "style", "");
12 | };
13 | },
14 | };
15 |
16 | export default website;
17 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/index.tsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from "react-dom";
2 | import { App } from "./components/app";
3 | import { LOG_LEVEL, logger } from "@/utils/logger";
4 |
5 | if (__DEV__) {
6 | logger.setLevel(LOG_LEVEL.INFO);
7 | }
8 |
9 | const darkThemeMatch = window.matchMedia("(prefers-color-scheme: dark)");
10 | if (darkThemeMatch.matches) {
11 | document.body.setAttribute("arco-theme", "dark");
12 | }
13 |
14 | ReactDOM.render(, document.getElementById("root"));
15 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/zhihu.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /link\.zhihu/,
5 | init: function () {
6 | const result = /.*link.zhihu.com\/\?target=(.*)/.exec(location.href);
7 | if (result) {
8 | const url = decodeURIComponent(result[1]);
9 | if (url) {
10 | console.log(url);
11 | location.href = url;
12 | }
13 | }
14 | },
15 | };
16 |
17 | export default website;
18 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/i18n/types.ts:
--------------------------------------------------------------------------------
1 | import type { en } from "./en";
2 |
3 | export type DefaultI18nConfig = typeof en;
4 |
5 | export type ConfigBlock = {
6 | [key: string]: string | ConfigBlock;
7 | };
8 |
9 | type FlattenKeys = Key extends string
10 | ? T[Key] extends ConfigBlock
11 | ? `${Key}.${FlattenKeys}`
12 | : `${Key}`
13 | : never;
14 |
15 | export type I18nTypes = Record, string>;
16 |
--------------------------------------------------------------------------------
/packages/copy/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | declare interface Document {
2 | selection: {
3 | createRange: () => {
4 | text: string;
5 | };
6 | };
7 | }
8 |
9 | declare function GM_xmlhttpRequest(params: {
10 | method: GET | POST;
11 | url: string;
12 | onload: (response: { status: number; responseText: string }) => void;
13 | }): void;
14 |
15 | declare const unsafeWindow = any;
16 |
17 | declare module "*.css" {
18 | const content: string;
19 | export default content;
20 | }
21 |
--------------------------------------------------------------------------------
/packages/site-director/src/websites.ts:
--------------------------------------------------------------------------------
1 | import google from "./modules/google";
2 | import zhihu from "./modules/zhihu";
3 | import csdn from "./modules/csdn";
4 | import jianshu from "./modules/jianshu";
5 | import qqMail from "./modules/qq-mail";
6 | import juejin from "./modules/juejin";
7 |
8 | export interface Website {
9 | regexp: RegExp;
10 | init: () => void;
11 | }
12 |
13 | const websites: Website[] = [google, zhihu, csdn, jianshu, qqMail, juejin];
14 |
15 | export default websites;
16 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "printWidth": 100,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": false,
7 | "quoteProps": "preserve",
8 | "jsxSingleQuote": false,
9 | "trailingComma": "es5",
10 | "bracketSpacing": true,
11 | "jsxBracketSameLine": false,
12 | "arrowParens": "avoid",
13 | "requirePragma": false,
14 | "insertPragma": false,
15 | "proseWrap": "preserve",
16 | "htmlWhitespaceSensitivity": "ignore",
17 | "endOfLine": "lf",
18 | };
19 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/header/index.tsx:
--------------------------------------------------------------------------------
1 | import { cs } from "laser-utils";
2 | import styles from "./index.module.scss";
3 | import type { FC } from "react";
4 | import type { I18n } from "@/popup/i18n";
5 |
6 | export const Header: FC<{
7 | i18n: I18n;
8 | }> = props => {
9 | const { i18n } = props;
10 |
11 | return (
12 |
13 |

14 |
{i18n.t("Title")}
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/leetcode.ts:
--------------------------------------------------------------------------------
1 | import { PAGE_LOADED } from "../constant/event";
2 | import utils from "../utils/event";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | regexp: new RegExp("leetcode"),
7 | init: function () {
8 | utils.hideButton();
9 | window.addEventListener(PAGE_LOADED, () => {
10 | utils.enableOnCopy("#lc-home");
11 | utils.enableOnCopy("[data-layout-path='/ts0/t1']");
12 | });
13 | },
14 | };
15 |
16 | export default website;
17 |
--------------------------------------------------------------------------------
/packages/force-copy/src/worker/index.ts:
--------------------------------------------------------------------------------
1 | import { LOG_LEVEL, logger } from "@/utils/logger";
2 | import { importWorkerScript } from "./runtime/script";
3 | import { CWBridge } from "@/bridge/content-worker";
4 | import { onContentMessage } from "./channel/content";
5 | import { initializeEvents } from "./runtime/initialize";
6 |
7 | (() => {
8 | if (__DEV__) {
9 | logger.setLevel(LOG_LEVEL.INFO);
10 | }
11 | initializeEvents();
12 | importWorkerScript();
13 | CWBridge.onContentMessage(onContentMessage);
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/site-director/src/modules/google.ts:
--------------------------------------------------------------------------------
1 | import type { Website } from "../websites";
2 |
3 | const website: Website = {
4 | regexp: /google/,
5 | init: function () {
6 | const isScholar = window.location.host.startsWith("scholar");
7 | const selector = isScholar ? "#gs_bdy_ccl .gs_rt a" : "#res a";
8 | document.addEventListener("DOMContentLoaded", () =>
9 | document.querySelectorAll(selector).forEach(item => item.setAttribute("target", "_blank"))
10 | );
11 | },
12 | };
13 |
14 | export default website;
15 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/worker-content/request.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex } from "@/utils/types";
2 | import { MARK } from "./constant";
3 |
4 | const WC_REQUEST_TYPE = ["DATA", "__"] as const;
5 | export const POPUP_TO_CONTENT_REQUEST = WC_REQUEST_TYPE.reduce(
6 | (acc, cur) => ({ ...acc, [cur]: `__${cur}__${MARK}__` }),
7 | {} as { [K in typeof WC_REQUEST_TYPE[number]]: `__${K}__${typeof MARK}__` }
8 | );
9 |
10 | type EventMap = {
11 | [POPUP_TO_CONTENT_REQUEST.DATA]: string;
12 | };
13 |
14 | export type WCRequestType = Reflex.Tuple;
15 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/common-e.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp(["wjx", "fanyi\\.baidu", "tianqi", "rrdynb", "fuwu7"].join("|")),
6 | init: function () {
7 | utils.hideButton();
8 | utils.enableUserSelectByCSS();
9 | utils.enableOnCopyByCapture();
10 | utils.enableOnKeyDownByCapture();
11 | utils.enableOnSelectStartByCapture();
12 | utils.enableOnContextMenuByCapture();
13 | },
14 | };
15 |
16 | export default website;
17 |
--------------------------------------------------------------------------------
/packages/force-copy/src/inject/types/website.ts:
--------------------------------------------------------------------------------
1 | import type { ActionType } from "@/utils/constant";
2 | import type { State } from "./state";
3 | import type { DOM_STAGE } from "copy/src/constant/event";
4 | import type { Object } from "@/utils/types";
5 |
6 | export type WebSite = {
7 | /** 链接匹配正则 */
8 | regexp: RegExp;
9 | /** 初始化必须执行 */
10 | init?: (state: State) => void;
11 | /** 启动时执行 初始启动/被动启动 */
12 | start: (type: ActionType, when: Object.Values) => void;
13 | /** 关闭时执行 被动关闭 */
14 | close: (type: ActionType) => void;
15 | };
16 |
--------------------------------------------------------------------------------
/packages/water-mark/src/utils/constant.ts:
--------------------------------------------------------------------------------
1 | export const FALLBACK_CLASS = "__WATERMARK__";
2 |
3 | export const OPACITY_PROPERTY = [
4 | "opacity: 0 !important;",
5 | "visibility: hidden !important;",
6 | "transform: translate(-999999px, -999999px) !important;",
7 | ].join("");
8 |
9 | export const OPACITY_BACKGROUND_PROPERTY = [
10 | "background: transparent !important;",
11 | "background-color: transparent !important;",
12 | "background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0)) !important;",
13 | ].join("");
14 |
15 | export const NOOP = () => null;
16 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/edu30.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: /.*30edu\.com\.cn\/.+/,
6 | init: function () {
7 | window.onload = () => {
8 | const iframes = document.getElementsByTagName("iframe");
9 | if (iframes.length === 2) {
10 | const body = iframes[1].contentWindow?.document.querySelector("body");
11 | body && utils.removeAttributes(body, ["oncopy", "oncontextmenu", "onselectstart"]);
12 | }
13 | };
14 | },
15 | };
16 |
17 | export default website;
18 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/i18n/en.ts:
--------------------------------------------------------------------------------
1 | export const en = {
2 | Title: "Force Copy",
3 | Captain: {
4 | Modules: "Modules",
5 | Start: "Start",
6 | Once: "Once",
7 | },
8 | Operation: {
9 | Copy: "Copy",
10 | Keyboard: "Keyboard",
11 | ContextMenu: "ContextMenu",
12 | },
13 | Information: {
14 | Tools: "Tools",
15 | GitHub: "GitHub",
16 | Help: "Help",
17 | Reload: "Reload",
18 | },
19 | Tools: {
20 | MouseEvent: "MouseEvent",
21 | FocusEvent: "FocusEvent",
22 | Editable: "Editable",
23 | PasteEvent: "PasteEvent",
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/packages/copy-currency/src/utils.ts:
--------------------------------------------------------------------------------
1 | export const styles = {
2 | insertCSS: (id: string, css: string): void => {
3 | const style = document.createElement("style");
4 | style.id = id;
5 | style.innerText = css;
6 | const [body] = document.getElementsByTagName("body");
7 | if (body) {
8 | body.appendChild(style);
9 | } else {
10 | window.addEventListener("DOMContentLoaded", () => document.body.appendChild(style));
11 | }
12 | },
13 | removeCSS: (id: string): void => {
14 | const style = document.getElementById(id);
15 | style && style.remove();
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-worker/request.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex } from "@/utils/types";
2 | import { MARK } from "./constant";
3 |
4 | const CW_REQUEST_TYPE = ["RELOAD", "SET_BADGE"] as const;
5 | export const CONTENT_TO_WORKER_REQUEST = CW_REQUEST_TYPE.reduce(
6 | (acc, cur) => ({ ...acc, [cur]: `__${cur}__${MARK}__` }),
7 | {} as { [K in typeof CW_REQUEST_TYPE[number]]: `__${K}__${typeof MARK}__` }
8 | );
9 |
10 | type EventMap = {
11 | [CONTENT_TO_WORKER_REQUEST.RELOAD]: null;
12 | [CONTENT_TO_WORKER_REQUEST.SET_BADGE]: number;
13 | };
14 |
15 | export type CWRequestType = Reflex.Tuple;
16 |
--------------------------------------------------------------------------------
/packages/force-copy/src/worker/utils/constant.ts:
--------------------------------------------------------------------------------
1 | export const CODE_PREFIX = [
2 | `if (window["${process.env.INJECT_FILE}"] && document instanceof XMLDocument === false) {`,
3 | ` const script = document.createElementNS("http://www.w3.org/1999/xhtml", "script");`,
4 | ` script.setAttribute("type", "text/javascript");`,
5 | ` const code = \`;(\${window["${process.env.INJECT_FILE}"].toString()})();\`;`,
6 | ].join("\n");
7 |
8 | export const CODE_SUFFIX = [
9 | ` document.documentElement.appendChild(script);`,
10 | ` script.remove();`,
11 | `}`,
12 | ].join("\n");
13 |
14 | export const NOOP = () => null;
15 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/common-p.ts:
--------------------------------------------------------------------------------
1 | import { DOM_STAGE } from "../constant/event";
2 | import utils from "../utils/event";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | config: {
7 | runAt: DOM_STAGE.START,
8 | },
9 | regexp: new RegExp(["examcoo"].join("|")),
10 | init: function () {
11 | utils.hideButton();
12 | utils.enableUserSelectByCSS();
13 | utils.enableOnCopyByCapture();
14 | utils.enableOnKeyDownByCapture();
15 | utils.enableOnSelectStartByCapture();
16 | utils.enableOnContextMenuByCapture();
17 | },
18 | };
19 |
20 | export default website;
21 |
--------------------------------------------------------------------------------
/packages/water-mark/src/utils/styles.ts:
--------------------------------------------------------------------------------
1 | import { styles } from "../../../copy-currency/src/utils";
2 |
3 | export const injectCSSEarly = (css: string) => {
4 | if (typeof GM_addStyle === "function") {
5 | GM_addStyle(css);
6 | return void 0;
7 | }
8 | const style = document.createElement("style");
9 | style.innerText = css;
10 | const head = document.head;
11 | if (head) {
12 | head.appendChild(style);
13 | return void 0;
14 | }
15 | const html = document.documentElement;
16 | if (html) {
17 | html.appendChild(style);
18 | return void 0;
19 | }
20 | styles.insertCSS(String(Math.random()), css);
21 | };
22 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-content/response.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex, Object } from "@/utils/types";
2 | import type { POPUP_TO_CONTENT_REQUEST } from "./request";
3 |
4 | export const PC_QUERY_STATE_ENUM = {
5 | COPY: "COPY",
6 | MENU: "MENU",
7 | KEYBOARD: "KEYBOARD",
8 | COPY_ONCE: "COPY_ONCE",
9 | MENU_ONCE: "MENU_ONCE",
10 | KEYBOARD_ONCE: "KEYBOARD_ONCE",
11 | } as const;
12 |
13 | export type PCQueryStateType = Object.Values;
14 |
15 | type EventMap = {
16 | [POPUP_TO_CONTENT_REQUEST.QUERY_STATE]: { [K in PCQueryStateType]: boolean };
17 | };
18 |
19 | export type PCResponseType = Reflex.Tuple;
20 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-worker/request.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex } from "@/utils/types";
2 | import { MARK } from "./constant";
3 |
4 | const PW_REQUEST_TYPE = ["RELOAD", "__"] as const;
5 | export const POPUP_TO_WORKER_REQUEST = PW_REQUEST_TYPE.reduce(
6 | (acc, cur) => ({ ...acc, [cur]: `__${cur}__${MARK}__` }),
7 | {} as { [K in typeof PW_REQUEST_TYPE[number]]: `__${K}__${typeof MARK}__` }
8 | );
9 |
10 | export type PWRequestMap = {
11 | [POPUP_TO_WORKER_REQUEST.RELOAD]: null;
12 | [POPUP_TO_WORKER_REQUEST.__]: null;
13 | };
14 |
15 | export type PWRequestType = Reflex.Tuple;
16 |
17 | export type PWRequestArgs = Reflex.Array;
18 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/zongheng.ts:
--------------------------------------------------------------------------------
1 | import utils from "../utils/event";
2 | import type { Website } from "../websites";
3 |
4 | const website: Website = {
5 | regexp: new RegExp("zongheng"),
6 | init: function () {
7 | utils.removeAttributes(".reader_box", ["style", "unselectable", "onselectstart"]);
8 | utils.removeAttributes(".reader_main", ["style", "unselectable", "onselectstart"]);
9 | utils.hideButton();
10 | utils.enableOnKeyDown("body");
11 | utils.enableUserSelectByCSS();
12 | utils.enableOnCopy(".content");
13 | utils.enableOnContextMenu("body");
14 | utils.enableOnSelectStart(".content");
15 | },
16 | };
17 |
18 | export default website;
19 |
--------------------------------------------------------------------------------
/packages/force-copy/src/content/index.ts:
--------------------------------------------------------------------------------
1 | import { PCBridge } from "@/bridge/popup-content";
2 | import { onReceiveReloadMsg } from "../utils/reload";
3 | import { onPopupMessage } from "./channel/popup";
4 | import { LOG_LEVEL, logger } from "@/utils/logger";
5 | import { initializeWorker } from "./runtime/initialize";
6 | import { isInIframe } from "@/utils/is";
7 | import { importInjectScript } from "./runtime/script";
8 |
9 | (() => {
10 | if (__DEV__) {
11 | !isInIframe && onReceiveReloadMsg();
12 | logger.setLevel(LOG_LEVEL.INFO);
13 | }
14 | logger.info("Content Script Loaded");
15 | importInjectScript();
16 | !isInIframe && initializeWorker();
17 | PCBridge.onPopupMessage(onPopupMessage);
18 | })();
19 |
--------------------------------------------------------------------------------
/packages/water-mark/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "default": "🔥🔥🔥移除页面水印🔥🔥🔥",
4 | "en": "Remove Page Watermark",
5 | "zh": "🔥🔥🔥移除页面水印🔥🔥🔥"
6 | },
7 | "namespace": "https://github.com/WindrunnerMax/TKScript",
8 | "version": "1.0.7",
9 | "description": {
10 | "default": "移除常见网页的水印",
11 | "en": "Remove watermarks from common web pages",
12 | "zh": "移除常见网页的水印"
13 | },
14 | "author": "Czy",
15 | "match": ["http://*/*", "https://*/*"],
16 | "supportURL": "https://github.com/WindrunnerMax/TKScript/issues",
17 | "license": "GPL License",
18 | "installURL": "https://github.com/WindrunnerMax/TKScript",
19 | "run-at": "document-start",
20 | "grant": ["GM_addStyle", "unsafeWindow"]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/youdao.ts:
--------------------------------------------------------------------------------
1 | import { MOUSE_DOWN, MOUSE_MOVE } from "../constant/event";
2 | import utils, { stopNativePropagation } from "../utils/event";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | config: {
7 | initCopyEvent: false,
8 | },
9 | regexp: /note\.youdao\.com\/newEditorV1\/bulb\.html.*/,
10 | init: function () {
11 | utils.hideButton();
12 | if (window.parent && window.parent.location.href.indexOf("ynoteshare") > -1) {
13 | utils.enableUserSelectByCSS();
14 | document.addEventListener(MOUSE_DOWN, stopNativePropagation, true);
15 | document.addEventListener(MOUSE_MOVE, stopNativePropagation, true);
16 | }
17 | },
18 | };
19 |
20 | export default website;
21 |
--------------------------------------------------------------------------------
/packages/expansion/expansion.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name 自动阅读全文
3 | // @namespace https://github.com/WindrunnerMax/TKScript
4 | // @version 1.0
5 | // @description try to take over the world!
6 | // @author Czy
7 | // @match https://blog.csdn.net/*
8 | // @match https://www.zhihu.com/*
9 | // @grant none
10 | // ==/UserScript==
11 |
12 | function show(dom) {
13 | dom[0] ? dom[0].click() : "";
14 | }
15 |
16 | (function () {
17 | "use strict";
18 |
19 | /* CSDN 展开阅读全文 */
20 | show(document.getElementsByClassName("btn-readmore"));
21 |
22 | /* 知乎 查看全部回答 */
23 | setTimeout(() => {
24 | show(document.getElementsByClassName("QuestionMainAction ViewAll-QuestionMainAction"));
25 | }, 1000);
26 | })();
27 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/kdocs.ts:
--------------------------------------------------------------------------------
1 | import { DOM_STAGE } from "../constant/event";
2 | import type { Website } from "../websites";
3 |
4 | export const kdoc: Website = {
5 | config: {
6 | runAt: DOM_STAGE.START,
7 | },
8 | regexp: new RegExp("kdocs"),
9 | init: function () {
10 | const patch = () => {
11 | unsafeWindow.APP && (unsafeWindow.APP.canCopy = () => true);
12 | };
13 | if (unsafeWindow.APP) {
14 | patch();
15 | } else {
16 | let APP: unknown = undefined;
17 | Object.defineProperty(unsafeWindow, "APP", {
18 | configurable: false,
19 | set: (value: unknown) => {
20 | APP = value;
21 | value && patch();
22 | },
23 | get: () => APP,
24 | });
25 | }
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/docin.ts:
--------------------------------------------------------------------------------
1 | import { PAGE_LOADED } from "../constant/event";
2 | import dom from "../utils/dom";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | regexp: new RegExp("docin.com/.*"),
7 | config: {
8 | initCopyEvent: false,
9 | captureInstance: true,
10 | delay: 100,
11 | },
12 | init: function () {
13 | window.addEventListener(PAGE_LOADED, () => dom.query("#j_select")?.click());
14 | dom.append("head", "");
15 | },
16 | getSelectedText: function () {
17 | if (unsafeWindow.docinReader && unsafeWindow.docinReader.st) {
18 | return unsafeWindow.docinReader.st;
19 | }
20 | return "";
21 | },
22 | };
23 |
24 | export default website;
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 问题描述
2 |
3 |
4 |
5 |
6 |
7 |
8 | ## 项目所属
9 |
10 |
11 |
12 | - [ ] Copy
13 | - [ ] Force Copy
14 | - [ ] Copy Currency
15 | - [ ] Site Director
16 | - [ ] Water Mark
17 | - [ ] Captcha
18 | - [ ] Expansion
19 | - [ ] Completion
20 | - [ ] Unknown
21 |
22 | ## 相关链接
23 |
24 |
25 |
26 |
27 |
28 |
29 | ## 预期表现
30 |
31 |
32 |
--------------------------------------------------------------------------------
/packages/force-copy/src/content/runtime/initialize.ts:
--------------------------------------------------------------------------------
1 | import { CWBridge } from "@/bridge/content-worker";
2 | import { CONTEXT_MENU_TYPE, COPY_TYPE, KEYBOARD_TYPE } from "@/utils/constant";
3 | import { Storage } from "laser-utils";
4 |
5 | export const initializeWorker = () => {
6 | Promise.resolve().then(() => {
7 | const badge = [
8 | Storage.local.get(COPY_TYPE),
9 | Storage.local.get(CONTEXT_MENU_TYPE),
10 | Storage.local.get(KEYBOARD_TYPE),
11 | Storage.session.get(COPY_TYPE),
12 | Storage.session.get(CONTEXT_MENU_TYPE),
13 | Storage.session.get(KEYBOARD_TYPE),
14 | ].filter(Boolean).length;
15 | CWBridge.postToWorker({ type: CWBridge.REQUEST.SET_BADGE, payload: badge });
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/packages/site-director/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "🔥🔥🔥跳转链接直达🔥🔥🔥",
3 | "namespace": "https://github.com/WindrunnerMax/TKScript",
4 | "version": "1.3.3",
5 | "description": "跳转链接直达,去掉确定跳转链接页面,用于谷歌、知乎、CSDN、简书",
6 | "author": "Czy",
7 | "match": [
8 | "*://*.google.com/*",
9 | "*://*.google.com.cn/*",
10 | "*://*.google.com.hk/*",
11 | "*://link.zhihu.com/*",
12 | "*://link.csdn.net/*",
13 | "*://link.juejin.cn/*",
14 | "*://www.jianshu.com/go-wild/*",
15 | "*://mail.qq.com/cgi-bin/readtemplate/*"
16 | ],
17 | "license": "MIT License",
18 | "supportURL": "https://github.com/WindrunnerMax/TKScript/issues",
19 | "installURL": "https://github.com/WindrunnerMax/TKScript",
20 | "grant": ["unsafeWindow", "GM_xmlhttpRequest"],
21 | "run-at": "document-start"
22 | }
23 |
--------------------------------------------------------------------------------
/packages/copy-currency/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "default": "🔥🔥🔥文本选中复制(通用)🔥🔥🔥",
4 | "en": "Text Copy Universal",
5 | "zh": "🔥🔥🔥文本选中复制(通用)🔥🔥🔥"
6 | },
7 | "namespace": "https://github.com/WindrunnerMax/TKScript",
8 | "version": "1.1.3",
9 | "description": {
10 | "default": "文本选中复制通用版本,适用于大多数网站",
11 | "en": "Text copy general version, suitable for most websites.",
12 | "zh": "文本选中复制通用版本,适用于大多数网站"
13 | },
14 | "author": "Czy",
15 | "match": ["http://*/*", "https://*/*"],
16 | "supportURL": "https://github.com/WindrunnerMax/TKScript/issues",
17 | "license": "GPL License",
18 | "installURL": "https://github.com/WindrunnerMax/TKScript",
19 | "run-at": "document-end",
20 | "grant": ["GM_registerMenuCommand", "GM_unregisterMenuCommand", "GM_notification"]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/hooks/use-memoized-fn.ts:
--------------------------------------------------------------------------------
1 | import { useMemo, useRef } from "react";
2 |
3 | type noop = (this: unknown, ...args: unknown[]) => never;
4 |
5 | type PickFunction = (
6 | this: ThisParameterType,
7 | ...args: Parameters
8 | ) => ReturnType;
9 |
10 | export const useMemoizedFn = (fn: T) => {
11 | const fnRef = useRef(fn);
12 |
13 | // why not write `fnRef.current = fn`?
14 | // https://github.com/alibaba/hooks/issues/728
15 | fnRef.current = useMemo(() => fn, [fn]);
16 |
17 | const memoizedFn = useRef>();
18 | if (!memoizedFn.current) {
19 | memoizedFn.current = function (this, ...args) {
20 | return fnRef.current.apply(this, args);
21 | };
22 | }
23 |
24 | return memoizedFn.current as T;
25 | };
26 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/footer/index.module.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | padding: 3px 5px 0;
3 | display: flex;
4 | align-items: center;
5 | font-size: 12px;
6 | justify-content: end;
7 |
8 | > a,
9 | div {
10 | cursor: pointer;
11 | color: var(--color-text-1);
12 | margin-left: 7px;
13 | display: flex;
14 | align-items: center;
15 | text-decoration: none;
16 |
17 | > svg {
18 | margin-right: 3px;
19 | }
20 | }
21 |
22 | :global {
23 | .arco-icon-question-circle,
24 | .arco-icon-experiment,
25 | .arco-icon-refresh {
26 | font-size: 14px;
27 | }
28 |
29 | .arco-icon-question-circle,
30 | .arco-icon-refresh {
31 | margin-left: -2px;
32 | }
33 |
34 | .arco-icon-experiment {
35 | margin-right: 2px;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2015",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "module": "esnext",
6 | "strict": true,
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "esModuleInterop": true,
10 | "allowSyntheticDefaultImports": true,
11 | "experimentalDecorators": true,
12 | "skipLibCheck": true,
13 | "strictNullChecks": true,
14 | "downlevelIteration": true,
15 | "declaration": false,
16 | "jsx": "react-jsx",
17 | "newLine": "lf",
18 | "paths": {
19 | "copy/*": ["./packages/copy/*"],
20 | "copy-currency/*": ["./packages/copy-currency/*"]
21 | }
22 | },
23 | "include": ["packages/*/src"],
24 | "exclude": ["node_modules"],
25 | "ts-node": {
26 | "compilerOptions": {
27 | "module": "commonjs"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/water-mark/src/utils/dom.ts:
--------------------------------------------------------------------------------
1 | import { FALLBACK_CLASS } from "./constant";
2 |
3 | export const inspectWaterMarkDOM = (node: Node) => {
4 | if (node instanceof HTMLElement === false) {
5 | return false;
6 | }
7 | if (node.classList.contains(FALLBACK_CLASS)) {
8 | return true;
9 | }
10 | if (!node.hasAttribute("style") || node.style.pointerEvents !== "none") {
11 | return false;
12 | }
13 | if (node instanceof HTMLImageElement && node.src && node.src.startsWith("data:")) {
14 | !node.classList.contains(FALLBACK_CLASS) && node.classList.add(FALLBACK_CLASS);
15 | return true;
16 | }
17 | if (node.style.background.startsWith("url") || node.style.backgroundImage.startsWith("url")) {
18 | !node.classList.contains(FALLBACK_CLASS) && node.classList.add(FALLBACK_CLASS);
19 | return true;
20 | }
21 | return false;
22 | };
23 |
--------------------------------------------------------------------------------
/packages/copy/src/constant/event.ts:
--------------------------------------------------------------------------------
1 | export const DOM_STAGE = {
2 | START: "document-start" as const,
3 | END: "document-end" as const,
4 | };
5 | export const DOM_READY = "DOMContentLoaded";
6 | export const DOM_LOADED = DOM_READY;
7 | export const PAGE_LOADED = "load";
8 | export const MOUSE_UP = "mouseup";
9 | export const MOUSE_DOWN = "mousedown";
10 | export const MOUSE_MOVE = "mousemove";
11 | export const COPY = "copy";
12 | export const SELECT_START = "selectstart";
13 | export const CONTEXT_MENU = "contextmenu";
14 | export const KEY_DOWN = "keydown";
15 | export const TOUCH_START = "touchstart";
16 | export const TOUCH_MOVE = "touchmove";
17 | export const TOUCH_END = "touchend";
18 | export const FOCUS = "focus";
19 | export const BLUR = "blur";
20 | export const FOCUS_IN = "focusin";
21 | export const FOCUS_OUT = "focusout";
22 | export const PASTE = "paste";
23 |
--------------------------------------------------------------------------------
/packages/copy/src/utils/is.ts:
--------------------------------------------------------------------------------
1 | const opt = Object.prototype.toString;
2 |
3 | export const isEmptyValue = (value: unknown): value is undefined | null => {
4 | return value === null || value === void 0;
5 | };
6 |
7 | export function isObject(value: unknown): value is Record {
8 | return opt.call(value) === "[object Object]";
9 | }
10 |
11 | export function isArray(value: unknown): value is unknown[] {
12 | return opt.call(value) === "[object Array]";
13 | }
14 |
15 | export function isNumber(value: unknown): value is number {
16 | return opt.call(value) === "[object Number]";
17 | }
18 |
19 | export function isPlainNumber(value: unknown): value is number {
20 | return /^(-|\+)?\d+(\.\d+)?$/.test(String(value));
21 | }
22 |
23 | export function isString(value: unknown): value is string {
24 | return opt.call(value) === "[object String]";
25 | }
26 |
--------------------------------------------------------------------------------
/packages/force-copy/script/reload/index.js:
--------------------------------------------------------------------------------
1 | const { IS_DEV } = require("../utils/node");
2 | const WebSocketServer = require("ws").Server;
3 |
4 | /**
5 | * @type {import("ws").WebSocket | null}
6 | */
7 | let wsClient = null;
8 |
9 | exports.ReloadPlugin = class ReloadPlugin {
10 | constructor() {
11 | if (IS_DEV) {
12 | try {
13 | const server = new WebSocketServer({ port: 3333 });
14 | server.on("connection", client => {
15 | wsClient && wsClient.close();
16 | wsClient = client;
17 | console.log("Client Connected");
18 | });
19 | } catch (error) {
20 | console.log("Auto Reload Server Error", error);
21 | }
22 | }
23 | }
24 | apply(compiler) {
25 | compiler.hooks.afterDone.tap("ReloadPlugin", () => {
26 | wsClient && wsClient.send("reload-app");
27 | });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/boke112.ts:
--------------------------------------------------------------------------------
1 | import dom from "../utils/dom";
2 | import utils from "../utils/event";
3 | import type { Website } from "../websites";
4 |
5 | const website: Website = {
6 | regexp: new RegExp(".+://boke112.com/post/.+"),
7 | init: function () {
8 | utils.enableOnCopyByCapture();
9 | const template = `
10 |
21 | `;
22 | dom.append("head", template);
23 | },
24 | };
25 |
26 | export default website;
27 |
--------------------------------------------------------------------------------
/packages/copy/src/index.ts:
--------------------------------------------------------------------------------
1 | import { initBaseEvent, initBaseStyle } from "./init";
2 | import { initWebsite, getSelectedText } from "./deploy";
3 | import instance from "./utils/instance";
4 | import { isEmptyContent } from "./utils/copy";
5 | import { MOUSE_UP } from "./constant/event";
6 |
7 | (function () {
8 | const websiteConfig = initWebsite();
9 | initBaseEvent(websiteConfig);
10 | initBaseStyle();
11 | window.addEventListener(
12 | MOUSE_UP,
13 | e => {
14 | const handler = () => {
15 | const content = getSelectedText();
16 | if (isEmptyContent(content)) {
17 | instance.hide();
18 | return void 0;
19 | }
20 | instance.onCopy(content, e);
21 | };
22 | websiteConfig.delay ? setTimeout(handler, websiteConfig.delay) : handler();
23 | },
24 | websiteConfig.captureInstance
25 | );
26 | })();
27 |
--------------------------------------------------------------------------------
/packages/force-copy/src/utils/reload.ts:
--------------------------------------------------------------------------------
1 | import { CWBridge } from "@/bridge/content-worker";
2 | import { cross } from "./global";
3 | import { logger } from "./logger";
4 |
5 | export const RELOAD_APP = "RELOAD_APP";
6 |
7 | export const onReceiveReloadMsg = () => {
8 | if (__DEV__) {
9 | try {
10 | const ws = new WebSocket("ws://localhost:3333");
11 | // 收到消息即重载
12 | ws.onmessage = () => {
13 | try {
14 | CWBridge.postToWorker({ type: CWBridge.REQUEST.RELOAD, payload: null });
15 | } catch (error) {
16 | logger.warning("SEND MESSAGE ERROR", error);
17 | }
18 | };
19 | } catch (error) {
20 | logger.warning("CONNECT ERROR", error);
21 | }
22 | }
23 | };
24 |
25 | export const reloadApp = (msg: unknown) => {
26 | if (__DEV__ && msg === RELOAD_APP) {
27 | cross.runtime.reload();
28 | logger.warning("RELOAD SUCCESS");
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/components/app/index.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from "react";
2 | import styles from "./index.module.scss";
3 | import { cs } from "laser-utils";
4 | import { I18n } from "../../i18n";
5 | import { cross } from "@/utils/global";
6 | import { Console } from "../console";
7 | import { Header } from "../header";
8 | import { Footer } from "../footer";
9 |
10 | // https://www.rfc-editor.org/rfc/rfc9110.html#name-language-tags
11 | // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/i18n
12 | const i18n = new I18n(cross.i18n.getUILanguage());
13 |
14 | export const App: FC = () => {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/packages/force-copy/src/popup/utils/badge.ts:
--------------------------------------------------------------------------------
1 | import { cross } from "@/utils/global";
2 |
3 | export const setBadgeNumber = (checked: boolean) => {
4 | cross.tabs
5 | .query({ active: true, currentWindow: true })
6 | .then(tabs => {
7 | const tab = tabs[0];
8 | const tabId = tab && tab.id;
9 | return tabId;
10 | })
11 | .then(tabId => {
12 | if (tabId) {
13 | let action: typeof cross.action | typeof cross.browserAction = cross.action;
14 | // #IFDEF GECKO
15 | action = cross.browserAction;
16 | // #ENDIF
17 | action.getBadgeText({ tabId }).then(text => {
18 | const badge = Number(text) || 0;
19 | const next = badge + (checked ? 1 : -1);
20 | action.setBadgeText({ text: next <= 0 ? "" : String(next), tabId });
21 | action.setBadgeBackgroundColor({ color: "#4e5969", tabId });
22 | });
23 | }
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/packages/copy/src/init.ts:
--------------------------------------------------------------------------------
1 | import appStyle from "./styles/app.css";
2 | import baseStyle from "./styles/style.css";
3 | import { COPY, DOM_READY } from "./constant/event";
4 | import type { WebsiteConfig } from "./websites";
5 | import dom from "./utils/dom";
6 |
7 | export const initBaseEvent = (websiteConfig: WebsiteConfig): void => {
8 | window.addEventListener(DOM_READY, () => {
9 | if (websiteConfig.initCopyEvent) {
10 | document.oncopy = e => e.stopPropagation();
11 | document.body.oncopy = e => e.stopPropagation();
12 | document.addEventListener(COPY, e => e.stopPropagation());
13 | document.body.addEventListener(COPY, e => e.stopPropagation());
14 | }
15 | });
16 | };
17 |
18 | export const initBaseStyle = (): void => {
19 | window.addEventListener(DOM_READY, () => {
20 | dom.append("head", ``);
21 | dom.append("head", ``);
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/packages/force-copy/script/if-def/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "if-def-processor",
3 | "version": "1.0.3",
4 | "files": [
5 | "index.js",
6 | "*.code-snippets"
7 | ],
8 | "main": "index.js",
9 | "sideEffects": false,
10 | "author": "Czy",
11 | "license": "MIT",
12 | "description": "Rspack/Webpack if-def predefined syntax loader",
13 | "scripts": {
14 | "publish:main": "npm publish --registry=https://registry.npmjs.org/",
15 | "publish:test": "npm publish --registry=https://registry.npmjs.org/ --dry-run"
16 | },
17 | "bugs": {
18 | "url": "https://github.com/WindrunnerMax/TKScript/issues"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/WindrunnerMax/TKScript"
23 | },
24 | "homepage": "https://github.com/WindrunnerMax/TKScript",
25 | "keywords": [
26 | "if-def",
27 | "rspack",
28 | "loader"
29 | ],
30 | "dependencies": {},
31 | "devDependencies": {}
32 | }
33 |
--------------------------------------------------------------------------------
/packages/force-copy/src/inject/utils/delay.ts:
--------------------------------------------------------------------------------
1 | import { DOM_READY, PAGE_LOADED } from "copy/src/constant/event";
2 | import { EVENTS_ENUM, EventBus } from "./bus";
3 |
4 | export const delayExecute = (
5 | when: typeof DOM_READY | typeof PAGE_LOADED = PAGE_LOADED,
6 | delayMax: number | false = 6000
7 | ) => {
8 | const delayWithEvent = new Promise(r => {
9 | const resolve = () => r();
10 | if (when === DOM_READY) {
11 | if (document.readyState !== "loading") {
12 | resolve();
13 | } else {
14 | EventBus.once(EVENTS_ENUM.DOM_LOADED, resolve);
15 | }
16 | return void 0;
17 | }
18 | if (document.readyState === "complete") {
19 | resolve();
20 | } else {
21 | EventBus.once(EVENTS_ENUM.PAGE_LOADED, resolve);
22 | }
23 | });
24 | const delayWithTimeout = delayMax && new Promise(resolve => setTimeout(resolve, delayMax));
25 | return Promise.race([delayWithEvent, delayWithTimeout].filter(Boolean));
26 | };
27 |
--------------------------------------------------------------------------------
/packages/copy/src/utils/dom.ts:
--------------------------------------------------------------------------------
1 | import { isString } from "./is";
2 |
3 | export const dom = {
4 | query: function (selector: string): null | HTMLElement {
5 | return document.querySelector(selector);
6 | },
7 | attr: function (selector: string, attr: string, value: string): void {
8 | const dom = document.querySelector(selector);
9 | dom && dom.setAttribute(attr, value);
10 | },
11 | append: function (selector: string, content: Element | string): HTMLDivElement {
12 | const container = document.createElement("div");
13 | if (isString(content)) {
14 | container.innerHTML = content;
15 | } else {
16 | container.appendChild(content);
17 | }
18 | const targetDOM = document.querySelector(selector);
19 | targetDOM && targetDOM.append(container);
20 | return container;
21 | },
22 | remove: function (selector: string): void {
23 | const targetDOM = document.querySelector(selector);
24 | targetDOM && targetDOM.remove();
25 | },
26 | };
27 |
28 | export default dom;
29 |
--------------------------------------------------------------------------------
/packages/copy-currency/src/index.css:
--------------------------------------------------------------------------------
1 | .__copy-currency-container{
2 | position: fixed;
3 | left: -150px;
4 | bottom: 0px;
5 | width: 150px;
6 | display: flex;
7 | flex-direction: column;
8 | border-radius: 3px;
9 | background-color: #4C98F7;
10 | transition: all .3s;
11 | z-index: 9999999999;
12 | }
13 |
14 | .__copy-currency-container::before{
15 | content: "";
16 | position: absolute;
17 | right: -6px;
18 | top: calc(50% - 10px);
19 | width: 20px;
20 | height: 20px;
21 | border-radius: 20px;
22 | background-color: #4C98F7;
23 | cursor: pointer;
24 | }
25 |
26 | .__copy-currency-container:hover{
27 | left: 0;
28 | }
29 |
30 | .__copy-currency-container > .__copy-currency-button{
31 | font-size: 12px !important;
32 | margin: 5px;
33 | cursor: pointer;
34 | color: #fff !important;
35 | border: 1px solid #fff;
36 | padding: 5px 3px 5px 4px;
37 | user-select: none;
38 | border-radius: 3px;
39 | z-index: 9999999999;
40 | text-align: center;
41 | }
--------------------------------------------------------------------------------
/.github/workflows/deploy-scripts.yml:
--------------------------------------------------------------------------------
1 | name: deploy-scripts gh-pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build-and-deploy:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: checkout
13 | uses: actions/checkout@v2
14 | with:
15 | fetch-depth: 0
16 | persist-credentials: false
17 |
18 | - name: install node-v16
19 | uses: actions/setup-node@v3
20 | with:
21 | node-version: '16.16.0'
22 |
23 | - name: install dependencies
24 | run: |
25 | node -v
26 | npm install -g pnpm@8.11.0
27 | pnpm --filter=\!force-copy --registry=https://registry.npmjs.org/ install
28 |
29 | - name: build project
30 | run: |
31 | pnpm run build:scripts
32 |
33 | - name: deploy
34 | uses: JamesIves/github-pages-deploy-action@releases/v3
35 | with:
36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 | BRANCH: gh-pages
38 | FOLDER: dist
39 |
--------------------------------------------------------------------------------
/packages/force-copy/script/utils/node.js:
--------------------------------------------------------------------------------
1 | const IS_DEV = process.env.NODE_ENV === "development";
2 | const IS_PROD = process.env.NODE_ENV === "production";
3 | const IS_GECKO = process.env.PLATFORM === "gecko";
4 | const IS_CHROMIUM = process.env.PLATFORM ? process.env.PLATFORM === "chromium" : true;
5 | const CHARTS = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm0123456789";
6 |
7 | exports.IS_DEV = IS_DEV;
8 | exports.IS_PROD = IS_PROD;
9 | exports.IS_GECKO = IS_GECKO;
10 | exports.IS_CHROMIUM = IS_CHROMIUM;
11 |
12 | const getUniqueId = (len = 10) => {
13 | const chars = new Array(len - 1).fill("");
14 | return (
15 | CHARTS[Math.floor(Math.random() * 52)] +
16 | chars.map(() => CHARTS[Math.floor(Math.random() * CHARTS.length)]).join("")
17 | );
18 | };
19 |
20 | const promisify = fn => {
21 | return (...args) =>
22 | new Promise((resolve, reject) => {
23 | fn(...args, (err, res) => {
24 | if (err) reject(err);
25 | else resolve(res);
26 | });
27 | });
28 | };
29 |
30 | exports.promisify = promisify;
31 | exports.getUniqueId = getUniqueId;
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Czy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/force-copy/src/utils/types.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-namespace */
2 |
3 | export namespace Object {
4 | export type KeyType = string | number | symbol;
5 |
6 | export type Keys> = keyof T;
7 |
8 | export type Values> = T[keyof T];
9 | }
10 |
11 | export namespace Array {
12 | export type Values = T[number];
13 | }
14 |
15 | export namespace String {
16 | export type Map = { [P in T]: P };
17 | }
18 |
19 | export namespace Reflex {
20 | type _Array> = T extends string
21 | ? [type: T, payload: unknown extends M[T] ? null : M[T]]
22 | : never;
23 |
24 | export type Array> = _Array, M>;
25 |
26 | type _Map> = {
27 | [P in T]: { type: P; payload: unknown extends M[P] ? never : M[P] };
28 | };
29 |
30 | export type Tuple> = Object.Values<_Map, M>>;
31 | }
32 |
--------------------------------------------------------------------------------
/packages/force-copy/script/manifest/index.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const tsNode = require("ts-node");
3 | const fs = require("fs");
4 | const { promisify, IS_GECKO } = require("../utils/node");
5 |
6 | const writeFile = promisify(fs.writeFile);
7 |
8 | exports.ManifestPlugin = class ManifestPlugin {
9 | constructor() {
10 | tsNode.register();
11 | this.manifest = path.resolve(`src/manifest/index.ts`);
12 | }
13 |
14 | apply(compiler) {
15 | compiler.hooks.make.tap("ManifestPlugin", compilation => {
16 | const manifest = this.manifest;
17 | !compilation.fileDependencies.has(manifest) && compilation.fileDependencies.add(manifest);
18 | });
19 |
20 | compiler.hooks.done.tapPromise("ManifestPlugin", () => {
21 | delete require.cache[require.resolve(this.manifest)];
22 | const manifest = require(this.manifest);
23 | const version = require(path.resolve("package.json")).version;
24 | manifest.version = version;
25 | const folder = IS_GECKO ? "build-gecko" : "build";
26 | return writeFile(path.resolve(`${folder}/manifest.json`), JSON.stringify(manifest, null, 2));
27 | });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/packages/force-copy/src/worker/channel/content.ts:
--------------------------------------------------------------------------------
1 | import { CWBridge } from "@/bridge/content-worker";
2 | import type { CWRequestType } from "@/bridge/content-worker/request";
3 | import { cross } from "@/utils/global";
4 | import { logger } from "@/utils/logger";
5 | import { RELOAD_APP, reloadApp } from "@/utils/reload";
6 |
7 | export const onContentMessage = (data: CWRequestType, sender: chrome.runtime.MessageSender) => {
8 | logger.info("Worker Receive Content Message", data);
9 | switch (data.type) {
10 | case CWBridge.REQUEST.RELOAD: {
11 | reloadApp(RELOAD_APP);
12 | break;
13 | }
14 | case CWBridge.REQUEST.SET_BADGE: {
15 | const { payload } = data;
16 | if (payload && sender.tab && sender.tab.id) {
17 | const tabId = sender.tab.id;
18 | let action: typeof cross.action | typeof cross.browserAction = cross.action;
19 | // #IFDEF GECKO
20 | action = cross.browserAction;
21 | // #ENDIF
22 | action.setBadgeText({ text: payload.toString(), tabId });
23 | action.setBadgeBackgroundColor({ color: "#4e5969", tabId });
24 | }
25 | break;
26 | }
27 | }
28 | return null;
29 | };
30 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-content/request.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex } from "@/utils/types";
2 | import { MARK } from "./constant";
3 |
4 | const PC_REQUEST_TYPE = [
5 | "COPY_TYPE",
6 | "KEYBOARD_TYPE",
7 | "CONTEXT_MENU_TYPE",
8 | "QUERY_STATE",
9 | "DEBUG_MOUSE_EVENT",
10 | "DEBUG_FOCUS_EVENT",
11 | "DEBUG_EDITABLE",
12 | "DEBUG_PASTE_EVENT",
13 | ] as const;
14 |
15 | export const POPUP_TO_CONTENT_REQUEST = PC_REQUEST_TYPE.reduce(
16 | (acc, cur) => ({ ...acc, [cur]: `__${cur}__${MARK}__` }),
17 | {} as { [K in typeof PC_REQUEST_TYPE[number]]: `__${K}__${typeof MARK}__` }
18 | );
19 |
20 | type EventMap = {
21 | [POPUP_TO_CONTENT_REQUEST.COPY_TYPE]: { checked: boolean; once: boolean };
22 | [POPUP_TO_CONTENT_REQUEST.KEYBOARD_TYPE]: { checked: boolean; once: boolean };
23 | [POPUP_TO_CONTENT_REQUEST.CONTEXT_MENU_TYPE]: { checked: boolean; once: boolean };
24 | [POPUP_TO_CONTENT_REQUEST.QUERY_STATE]: null;
25 | [POPUP_TO_CONTENT_REQUEST.DEBUG_MOUSE_EVENT]: null;
26 | [POPUP_TO_CONTENT_REQUEST.DEBUG_FOCUS_EVENT]: null;
27 | [POPUP_TO_CONTENT_REQUEST.DEBUG_EDITABLE]: null;
28 | [POPUP_TO_CONTENT_REQUEST.DEBUG_PASTE_EVENT]: null;
29 | };
30 |
31 | export type PCRequestType = Reflex.Tuple;
32 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-inject/request.ts:
--------------------------------------------------------------------------------
1 | import type { Reflex, Object } from "@/utils/types";
2 | import { MARK } from "./constant";
3 |
4 | const CI_REQUEST_ENUM = [
5 | "COPY_TYPE",
6 | "KEYBOARD_TYPE",
7 | "CONTEXT_MENU_TYPE",
8 | "DEBUG_MOUSE_EVENT",
9 | "DEBUG_FOCUS_EVENT",
10 | "DEBUG_EDITABLE",
11 | "DEBUG_PASTE",
12 | ] as const;
13 |
14 | export const CONTENT_TO_INJECT_REQUEST = CI_REQUEST_ENUM.reduce(
15 | (acc, cur) => ({ ...acc, [cur]: `__${cur}__${MARK}__` }),
16 | {} as { [K in typeof CI_REQUEST_ENUM[number]]: `__${K}__${typeof MARK}__` }
17 | );
18 |
19 | export const CI_EXECUTION_ENUM = {
20 | START: "START",
21 | CLOSE: "CLOSE",
22 | } as const;
23 |
24 | export type CIExecutionType = Object.Values;
25 |
26 | export type EventMap = {
27 | [CONTENT_TO_INJECT_REQUEST.COPY_TYPE]: CIExecutionType;
28 | [CONTENT_TO_INJECT_REQUEST.KEYBOARD_TYPE]: CIExecutionType;
29 | [CONTENT_TO_INJECT_REQUEST.CONTEXT_MENU_TYPE]: CIExecutionType;
30 | [CONTENT_TO_INJECT_REQUEST.DEBUG_MOUSE_EVENT]: null;
31 | [CONTENT_TO_INJECT_REQUEST.DEBUG_FOCUS_EVENT]: null;
32 | [CONTENT_TO_INJECT_REQUEST.DEBUG_EDITABLE]: null;
33 | [CONTENT_TO_INJECT_REQUEST.DEBUG_PASTE]: null;
34 | };
35 |
36 | export type CIRequestType = Reflex.Tuple;
37 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/popup-worker/index.ts:
--------------------------------------------------------------------------------
1 | import { cross } from "@/utils/global";
2 | import type { PWRequestType } from "./request";
3 | import { POPUP_TO_WORKER_REQUEST } from "./request";
4 | import { MARK } from "./constant";
5 |
6 | export class PWBridge {
7 | public static readonly REQUEST = POPUP_TO_WORKER_REQUEST;
8 |
9 | static async postToWorker(data: PWRequestType) {
10 | return new Promise(resolve => {
11 | if (cross.runtime.id) {
12 | cross.runtime.sendMessage(data).then(resolve);
13 | } else {
14 | resolve(null);
15 | }
16 | });
17 | }
18 |
19 | static onPopupMessage(cb: (data: PWRequestType, sender: chrome.runtime.MessageSender) => null) {
20 | const handler = (
21 | message: PWRequestType,
22 | sender: chrome.runtime.MessageSender,
23 | sendResponse: (response?: null) => void
24 | ) => {
25 | const rtn = cb(message, sender);
26 | sendResponse(rtn || null);
27 | };
28 | cross.runtime.onMessage.addListener(handler);
29 | return () => {
30 | cross.runtime.onMessage.removeListener(handler);
31 | };
32 | }
33 |
34 | static isPWRequestType(data: PWRequestType): data is PWRequestType {
35 | return data && data.type && data.type.endsWith(`__${MARK}__`);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-worker/index.ts:
--------------------------------------------------------------------------------
1 | import { cross } from "@/utils/global";
2 | import type { CWRequestType } from "./request";
3 | import { CONTENT_TO_WORKER_REQUEST } from "./request";
4 | import { MARK } from "./constant";
5 |
6 | export class CWBridge {
7 | public static readonly REQUEST = CONTENT_TO_WORKER_REQUEST;
8 |
9 | static async postToWorker(data: CWRequestType) {
10 | return new Promise(resolve => {
11 | if (cross.runtime.id) {
12 | cross.runtime.sendMessage(data).then(resolve);
13 | } else {
14 | resolve(null);
15 | }
16 | });
17 | }
18 |
19 | static onContentMessage(cb: (data: CWRequestType, sender: chrome.runtime.MessageSender) => null) {
20 | const handler = (
21 | message: CWRequestType,
22 | sender: chrome.runtime.MessageSender,
23 | sendResponse: (response?: null) => void
24 | ) => {
25 | const rtn = cb(message, sender);
26 | sendResponse(rtn || null);
27 | };
28 | cross.runtime.onMessage.addListener(handler);
29 | return () => {
30 | cross.runtime.onMessage.removeListener(handler);
31 | };
32 | }
33 |
34 | static isCWRequestType(data: CWRequestType): data is CWRequestType {
35 | return data && data.type && data.type.endsWith(`__${MARK}__`);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/force-copy/src/bridge/content-inject/index.ts:
--------------------------------------------------------------------------------
1 | import { decodeJSON, encodeJSON, isUndefined } from "laser-utils";
2 | import type { CIRequestType } from "./request";
3 | import { CONTENT_TO_INJECT_REQUEST } from "./request";
4 | import { EVENT_TYPE, MARK } from "./constant";
5 |
6 | export class CIBridge {
7 | public static readonly REQUEST = CONTENT_TO_INJECT_REQUEST;
8 |
9 | static postToInject(data: CIRequestType) {
10 | window.dispatchEvent(new CustomEvent(EVENT_TYPE, { detail: encodeJSON(data) }));
11 | }
12 |
13 | static onContentMessage(cb: (data: CIRequestType) => void) {
14 | const handler = (event: CustomEvent) => {
15 | const data = decodeJSON(event.detail);
16 | if (data && data.type && !isUndefined(data.payload)) {
17 | cb(data);
18 | }
19 | };
20 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
21 | // @ts-ignore
22 | window.addEventListener(EVENT_TYPE, handler);
23 | return () => {
24 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
25 | // @ts-ignore
26 | window.removeEventListener(EVENT_TYPE, handler);
27 | };
28 | }
29 |
30 | static isCIRequestType(data: CIRequestType): data is CIRequestType {
31 | return data && data.type && data.type.endsWith(`__${MARK}__`);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint:recommended", "plugin:prettier/recommended"],
3 | env: {
4 | browser: true,
5 | node: true,
6 | commonjs: true,
7 | es2021: true,
8 | },
9 | parserOptions: {
10 | requireConfigFile: false,
11 | ecmaVersion: 2020,
12 | sourceType: "module",
13 | },
14 | overrides: [
15 | {
16 | files: ["*.ts"],
17 | parser: "@typescript-eslint/parser",
18 | plugins: ["@typescript-eslint"],
19 | extends: ["plugin:@typescript-eslint/recommended"],
20 | },
21 | {
22 | files: ["*.tsx"],
23 | parser: "@typescript-eslint/parser",
24 | plugins: ["react", "react-hooks", "@typescript-eslint/eslint-plugin"],
25 | extends: ["plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"],
26 | },
27 | ],
28 | ignorePatterns: ["node_modules", "build", "dist", "coverage", "public"],
29 | rules: {
30 | "semi": "error",
31 | "quote-props": ["error", "consistent-as-needed"],
32 | "arrow-parens": ["error", "as-needed"],
33 | "no-var": "error",
34 | "prefer-const": "error",
35 | "no-console": "off",
36 | "@typescript-eslint/explicit-module-boundary-types": "off",
37 | "@typescript-eslint/ban-ts-ignore": "off",
38 | "@typescript-eslint/ban-ts-comment": "off",
39 | "@typescript-eslint/consistent-type-imports": "error",
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/packages/force-copy/README.md:
--------------------------------------------------------------------------------
1 | # Force Copy
2 |
3 | Force Copy professionally circumvents limitations pertaining to Web Copying, Keyboard Usage, and Right-click Functionalities, facilitating an unhindered browsing experience.
4 |
5 | ## Install
6 |
7 | * [Firefox Add-Ons](https://addons.mozilla.org/en-US/firefox/addon/force-copy/)
8 | * [Chrome Web Store](https://chrome.google.com/webstore/detail/force-copy/cceclgeciefpanebkfkogecbjjchmico)
9 | * [GitHub Releases](https://github.com/WindrunnerMax/TKScript/releases)
10 |
11 | ## Release
12 |
13 | ```bash
14 | $ pnpm install
15 | $ pnpm run build # Chromium
16 | $ pnpm run build:gecko # Gecko
17 | ```
18 |
19 | ## Notice
20 |
21 |
22 |
23 | All functions of the extension are turned off by default. When you need it, click the extension program and select the corresponding module to start it.
24 |
25 | ⭐ Start means that the domain name remains open. Even if the page is closed, it will still remain started the next time it is opened.
26 | ⭐ Once means that it will only take effect in the current Tab page. After closing the Tab page, it will remain closed the next time it is opened. Note that refreshing the page will not turn off the function. This is useful in many situations, especially in rich text editor websites.
27 |
28 | Open source address: https://github.com/WindrunnerMax/TKScript.
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/packages/completion/completion.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name 阿里图标库CDN添加HTTP按钮
3 | // @namespace https://github.com/WindrunnerMax/TKScript
4 | // @version 1.0
5 | // @description try to take over the world!
6 | // @author You
7 | // @match https://www.iconfont.cn/manage/*manage_type=myprojects*
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | function addProtocol() {
12 | const preTags = document.getElementsByTagName("pre");
13 | const n = preTags.length;
14 | for (let i = 0; i < n; ++i)
15 | preTags[i].innerText = preTags[i].innerText.replace(
16 | /\/\/at.alicdn.com/g,
17 | "https://at.alicdn.com"
18 | );
19 | }
20 |
21 | (function () {
22 | "use strict";
23 | console.log(document.getElementsByClassName("block-bar"));
24 | const btn = document.createElement("div");
25 | btn.style.position = "fixed";
26 | btn.style.top = "35%";
27 | btn.style.left = "10px";
28 | btn.style.background = "#4C98F7";
29 | btn.style.color = "#fff";
30 | btn.style.height = "50px";
31 | btn.style.width = "50px";
32 | btn.style.cursor = "pointer";
33 | btn.style["line-height"] = "50px";
34 | btn.style["text-align"] = "center";
35 | btn.style["border-radius"] = "50px";
36 | btn.innerText = "HTTP";
37 | const body = document.getElementsByTagName("body")[0];
38 | btn.onclick = function () {
39 | addProtocol();
40 | };
41 | body.appendChild(btn);
42 | })();
43 |
--------------------------------------------------------------------------------
/packages/copy/src/modules/doc88.ts:
--------------------------------------------------------------------------------
1 | import dom from "../utils/dom";
2 | import type { Website } from "../websites";
3 |
4 | /*!
5 | * 外部引用 static.doc88.com 声明
6 | * 此部分是在处理 doc88.com 才会加载的资源文件,此资源文件由该网站加载时提供
7 | */
8 |
9 | let path = "";
10 | const website: Website = {
11 | regexp: /.*doc88\.com\/.+/,
12 | init: () => {
13 | dom.append(
14 | "body",
15 | ``
16 | );
17 | GM_xmlhttpRequest({
18 | method: "GET",
19 | url: "https://res3.doc88.com/resources/js/modules/main-v2.min.js?v=3.55",
20 | onload: function (response) {
21 | const result = /\("#cp_textarea"\).val\(([\S]*?)\);/.exec(response.responseText);
22 | if (result) path = result[1];
23 | },
24 | });
25 | window.addEventListener("load", () => {
26 | const cpFn = unsafeWindow.copyText.toString();
27 | const fnResult = /