├── Pagetual ├── version ├── pagetual.schema.json └── README.md ├── A Real Me ├── README.md └── ARealMe.user.js ├── Kill TieBa AD ├── README.md └── Kill TieBa AD.user.js ├── Valentine's Day ├── README.md ├── css │ └── default.css ├── js │ ├── functions.js │ └── garden.js └── Valentine's Day.user.js ├── BingBgForBaidu ├── README.md ├── bd.jpg └── BingBgForGoogle.user.js ├── Disable AD of ThisAV ├── README.md ├── av.jpg └── Disable AD of ThisAV.user.js ├── Mouse Gestures ├── case.gif ├── README.md └── Mouse Gestures.user.js ├── RandomSexyPic ├── case1.jpg ├── case2.jpg ├── case3.jpg ├── case4.jpg ├── case5.jpg └── README.md ├── Picviewer CE+ ├── customRule.png ├── gallery.html ├── pvcep_pdf_addon.user.js └── README.md ├── FlashViewer-HTML5 Video ├── showcase.jpg └── README.md ├── .gitignore ├── .github ├── FUNDING.yml ├── workflows │ ├── json-validator.yml │ ├── build-dist.yml │ ├── main.yml │ ├── jekyll-gh-pages.yml │ └── update_version.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── custom-rule-request.md │ └── bug_report.md ├── Invite Code Tool ├── README.md └── Invite Code Tool.user.js ├── Select All Checkboxes ├── README.md └── Select All Checkboxes.user.js ├── Messi └── messi.user.js ├── Highlight Every Code ├── README.md └── Highlight Every Code.user.js ├── SearchJumper ├── HideSaladict.user.js ├── searchJumperPinyinAddon.lib.js └── searchJumperLevenshteinAddon.lib.js ├── Switch Traditional Chinese and Simplified Chinese ├── README.md ├── lib │ ├── package.json │ ├── stcasc.d.ts │ └── test.js └── run.py ├── True URL downloads ├── README.md └── manageLinks.js ├── Bilibili Bangumi Cover └── Bilibili Bangumi Cover.user.js ├── HacgGodTurn ├── README.md └── od.js ├── Anti-anti-pic-stealing-link └── Anti-anti-pic-stealing-link.user.js ├── Appinn Comment └── AppinnComment.user.js ├── README.md ├── CODE_OF_CONDUCT.md ├── MoreSteamRatings └── MoreSteamRatings.user.js ├── Easy offline ├── README.MD └── Easy offline pikpak.user.js ├── X-Downloader └── X-Downloader.user.js └── DownloadAllContent └── DownloadAllContentSavaAsZIP.user.js /Pagetual/version: -------------------------------------------------------------------------------- 1 | 102 2 | -------------------------------------------------------------------------------- /A Real Me/README.md: -------------------------------------------------------------------------------- 1 | # Show results for A Real Me 2 | -------------------------------------------------------------------------------- /Kill TieBa AD/README.md: -------------------------------------------------------------------------------- 1 | Not maintained anymore 2 | === 3 | -------------------------------------------------------------------------------- /Valentine's Day/README.md: -------------------------------------------------------------------------------- 1 | Not maintained anymore 2 | === 3 | -------------------------------------------------------------------------------- /BingBgForBaidu/README.md: -------------------------------------------------------------------------------- 1 | # 百度首页美化,使用每日更新的 bing 图作为背景,添加万年历 2 | ![img](bd.jpg) 3 | -------------------------------------------------------------------------------- /Disable AD of ThisAV/README.md: -------------------------------------------------------------------------------- 1 | # 为 THISAV 添加視頻下載按鈕,去除首次點擊彈窗、導航廣告 2 | ![av](av.jpg) 3 | -------------------------------------------------------------------------------- /BingBgForBaidu/bd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/BingBgForBaidu/bd.jpg -------------------------------------------------------------------------------- /Mouse Gestures/case.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/Mouse Gestures/case.gif -------------------------------------------------------------------------------- /RandomSexyPic/case1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/RandomSexyPic/case1.jpg -------------------------------------------------------------------------------- /RandomSexyPic/case2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/RandomSexyPic/case2.jpg -------------------------------------------------------------------------------- /RandomSexyPic/case3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/RandomSexyPic/case3.jpg -------------------------------------------------------------------------------- /RandomSexyPic/case4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/RandomSexyPic/case4.jpg -------------------------------------------------------------------------------- /RandomSexyPic/case5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/RandomSexyPic/case5.jpg -------------------------------------------------------------------------------- /Disable AD of ThisAV/av.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/Disable AD of ThisAV/av.jpg -------------------------------------------------------------------------------- /Picviewer CE+/customRule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/Picviewer CE+/customRule.png -------------------------------------------------------------------------------- /FlashViewer-HTML5 Video/showcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoothin/UserScripts/HEAD/FlashViewer-HTML5 Video/showcase.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.vcs-cache 3 | VIP Video Cracker/VIP Video Cracker.user.js 4 | Picviewer CE+/package-lock.json 5 | Pagetual/guide/* 6 | Pagetual/guide/ 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | ko_fi: hoothin 3 | custom: ["https://paypal.me/hoothin", "https://afdian.com/a/hoothin"] 4 | -------------------------------------------------------------------------------- /Invite Code Tool/README.md: -------------------------------------------------------------------------------- 1 | Not maintained anymore 2 | === 3 | 4 | [注冊邀請碼助手](https://chrome.google.com/webstore/detail/ndmlflmkmohjoechiepcpflbljadmemp) 5 | --- 6 | -------------------------------------------------------------------------------- /Select All Checkboxes/README.md: -------------------------------------------------------------------------------- 1 | Select All Checkboxes 2 | = 3 | Useage 4 | - 5 | * Select all checkboxes by press **`Ctrl+Alt+mouse1`** 6 | * Or select checkboxes with mouse over by press **`Alt`** 7 | * Or select checkboxes between 2 marks by press **`Shift`** 8 | -------------------------------------------------------------------------------- /FlashViewer-HTML5 Video/README.md: -------------------------------------------------------------------------------- 1 | # [FlashViewer⬇️](https://hoothin.github.io/UserScripts/FlashViewer-HTML5%20Video/flashViewer.user.js) 2 | HTML5 視頻增強腳本 3 | 4 | 原作者 NLF 5 | 6 | 在 NLF 的腳本基礎上添加了**自定義視頻速度**、**更改視頻比例**與**自定義亮度**功能並做了些許優化。彈出視頻後在工具欄右側即可看到。 7 | 8 | 長按三倍速,在視頻上左右拖動滑鼠微調進度。 9 | 10 | ![showcase](showcase.jpg) 11 | -------------------------------------------------------------------------------- /Mouse Gestures/README.md: -------------------------------------------------------------------------------- 1 | Greasemonkey Mouse Gestures 2 | === 3 | 预置的鼠标手势: 4 | --- 5 | - ↓↑↓ = 用谷歌翻译当前网页或者选中单词 6 | - ↓↑↓← = 解除当前页面右键、复制、选择等限制 7 | - ↓↑↓→ = 显示淘宝天猫评论买家秀图片 8 | - ↓↑↓↑ = 查看当前页面所使用的各种技术 9 | - ↓→ = 关闭当前页面(标签) 10 | - ←↑ = 滚动至页头 11 | - ←↓ = 滚动至页尾 12 | - →↑← = 后退 13 | - ←↑→ = 前进 14 | - →↑ = 新建页(标签) 15 | - ↑↓ = 刷新 16 | 17 | ![case](case.gif) 18 | refer to "My Mouse Gestures"-ver.0.0.7 of Peer Zeng at [http://userscripts-mirror.org/scripts/show/463904], thanks to him -------------------------------------------------------------------------------- /Messi/messi.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 新浪法甲 3 | // @namespace hoothin 4 | // @version 0.1 5 | // @description 赛程列表滚动 6 | // @author hoothin 7 | // @match http://sports.sina.com.cn/g/ligue1/ 8 | // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 9 | // @grant GM_addStyle 10 | // ==/UserScript== 11 | 12 | (function() { 13 | 'use strict'; 14 | GM_addStyle(".results{overflow: overlay;padding: 10px;width: 380px;}.result_wrap{width: 380px;}"); 15 | })(); -------------------------------------------------------------------------------- /.github/workflows/json-validator.yml: -------------------------------------------------------------------------------- 1 | name: Validate JSON 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - 'Pagetual/pagetualRules.json' 7 | 8 | jobs: 9 | validate-json: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: json-yaml-validate 16 | uses: GrantBirki/json-yaml-validate@v3.0.0 17 | id: json-yaml-validate 18 | with: 19 | json_schema: Pagetual/pagetual.schema.json 20 | files: | 21 | Pagetual/pagetualRules.json -------------------------------------------------------------------------------- /RandomSexyPic/README.md: -------------------------------------------------------------------------------- 1 | Random sexy pictures 2 | === 3 | Browsing assistance for [Lolicon sexy pictures Api](https://api.lolicon.app/setu/v2?r18=1&num=5) 4 | --- 5 | 6 | Can be used to preview pictures with **any other JSON api**.
Just open the api and click the "Parse current api" under command menu, and click again & cancel to disable.
7 | For example: https://wall.alphacoders.com/api2.0/get.php?method=highest_rated&page=1&info_level=2&page=2 8 | 9 | ![case1](case1.jpg)![case2](case2.jpg)![case3](case3.jpg)![case4](case4.jpg)![case5](case5.jpg) 10 | -------------------------------------------------------------------------------- /Highlight Every Code/README.md: -------------------------------------------------------------------------------- 1 | Highlighting and beautify for code snippets 2 | 3 | Select code snippets with (*`Alt key`*) or (*`Ctrl key`*) or (*`Shift key`*) or (*`Meta key`*) 4 | === 5 | 6 | You can input custom code to get Highlighting and beautify with command menu when you don't select anything 7 | 8 | Use [prettify.js](http://groups.google.com/group/js-code-prettifier) to highlight 9 | and [js-beautify](http://jsbeautifier.org/) to format 10 | 11 | Support on JS (also effect on JSON) CSS HTML 12 | 13 | Test case:`{"alpha":416,"green":710}`. Select this with funcKeys and click the icon. 14 | -------------------------------------------------------------------------------- /Picviewer CE+/gallery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Picviewer CE+ 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /SearchJumper/HideSaladict.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Hide saladict icon 3 | // @name:zh-CN 隐藏沙拉查词图标 4 | // @namespace hoothin 5 | // @version 2024-07-19 6 | // @description Hide saladict icon for SearchJumper 7 | // @description:zh-CN 隐藏沙拉查词图标,转而用搜索酱来调用,以避免遮挡 8 | // @author hoothin 9 | // @match *://*/* 10 | // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 11 | // @grant GM_addStyle 12 | // ==/UserScript== 13 | 14 | (function() { 15 | 'use strict'; 16 | //搜索酱沙拉查词引擎: #p{click(#saladict-saladbowl-root>.saladict-external \=>> .isAnimate>div)} 17 | GM_addStyle(` 18 | #saladict-saladbowl-root.saladict-div.saladict-external { 19 | display:none!important; 20 | } 21 | `) 22 | })(); -------------------------------------------------------------------------------- /A Real Me/ARealMe.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name A Real Me 3 | // @namespace hoothin 4 | // @version 0.1 5 | // @description Show results for A Real Me 6 | // @author hoothin 7 | // @match https://www.arealme.com/* 8 | // @match http://www.anol.cn/* 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | (function() { 13 | 'use strict'; 14 | function showResult(){ 15 | var answers=document.querySelectorAll("div.answer"); 16 | [].forEach.call(answers,function(item){ 17 | item.innerHTML+=" "+item.getAttribute("value")+""; 18 | }); 19 | } 20 | showResult(); 21 | var start=document.querySelector("#start"); 22 | if(start){ 23 | start.onclick=e=>{setTimeout(()=>{showResult()},1000)}; 24 | } 25 | })(); -------------------------------------------------------------------------------- /Pagetual/pagetual.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Sites data", 3 | "description": "Object containing site config", 4 | "type": "array", 5 | "items": { 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "title": "Site Name", 10 | "description": "The site's name.", 11 | "examples": [ 12 | "Google" 13 | ], 14 | "type": "string" 15 | }, 16 | "url": { 17 | "title": "Site Url", 18 | "description": "The Regexp of site's url.", 19 | "examples": [ 20 | "^https:\/\/google\\.com\/" 21 | ], 22 | "type": "string" 23 | } 24 | }, 25 | "required": ["name", "url"] 26 | } 27 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project. Please publish the issue according to the 4 | guidelines, otherwise the request will be ignored and closed directly. Your understanding 5 | and cooperation are appreciated. 6 | title: '' 7 | labels: '' 8 | assignees: '' 9 | 10 | --- 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom-rule-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom rule request 3 | about: Seek help for custom rule. Please publish the issue according to the guidelines, 4 | otherwise the request ⚠will be ignored and closed directly⚠. Your understanding and 5 | cooperation are appreciated. 6 | title: '' 7 | labels: '' 8 | assignees: '' 9 | 10 | --- 11 | 12 | **The url of site** 13 | The example urls of site. ⚠**Do not paste only domain without pathname, or I'll close the issue without explanation**⚠. 14 | 15 | **Is your request related to a problem? Please describe.** 16 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 17 | 18 | **Describe the result you'd like with the rule** 19 | A clear and concise description of what you want to happen. 20 | 21 | **Custom rule you've tried** 22 | The rule you've made before. 23 | 24 | **Additional context** 25 | Add any other context or screenshots about the feature request here. 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve. Please publish the issue according to the 4 | guidelines, otherwise the request will be ignored and closed directly. Your understanding 5 | and cooperation are appreciated. 6 | title: '' 7 | labels: '' 8 | assignees: '' 9 | 10 | --- 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Desktop (please complete the following information):** 29 | - OS: [e.g. Mac] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Smartphone (please complete the following information):** 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /SearchJumper/searchJumperPinyinAddon.lib.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name SearchJumper pinyin addon 3 | // @name:zh-CN 搜索酱拼音扩展 4 | // @name:zh-TW 搜尋醬拼音擴展 5 | // @namespace hoothin 6 | // @version 0.3 7 | // @description Add pinyin support for SearchJumper 8 | // @description:zh-CN 为搜索酱的页内高亮查找添加拼音支持 9 | // @description:zh-TW 為搜尋醬的頁内高亮查找添加拼音支援 10 | // @author hoothin 11 | // @match *://*/* 12 | // @grant unsafeWindow 13 | // @run-at document-start 14 | // @require https://unpkg.com/pinyin-match/dist/traditional.js 15 | // ==/UserScript== 16 | 17 | (function() { 18 | 'use strict'; 19 | var _unsafeWindow = (typeof unsafeWindow == 'undefined') ? window : unsafeWindow; 20 | if (!_unsafeWindow.searchJumperAddons) _unsafeWindow.searchJumperAddons = []; 21 | var { match } = PinyinMatch; 22 | var pinyinSearch = (text, pinyin) => { 23 | let matchResult = match(text, pinyin); 24 | if (matchResult) { 25 | return {matched: true, pos: matchResult[0], len: matchResult[matchResult.length - 1] - matchResult[0] + 1}; 26 | } 27 | return {matched: false}; 28 | } 29 | _unsafeWindow.searchJumperPinyin = pinyinSearch; 30 | _unsafeWindow.searchJumperAddons.push({ 31 | sort: 1, 32 | name: "拼音", 33 | type: "findInPage", 34 | run: pinyinSearch 35 | }); 36 | })(); -------------------------------------------------------------------------------- /.github/workflows/build-dist.yml: -------------------------------------------------------------------------------- 1 | name: Build Picviewer CE+ Dist 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'Picviewer CE*/Picviewer CE*.user.js' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Replace require paths, add timestamp, and create dist file 20 | run: | 21 | sed -E \ 22 | -e "s#https://update.greasyfork.org/scripts/6158/([0-9]+)/GM_config%20CN.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/GM_config%20CN.js?v=\1#g" \ 23 | -e "s#https://update.greasyfork.org/scripts/438080/([0-9]+)/pvcep_rules.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_rules.js?v=\1#g" \ 24 | -e "s#https://update.greasyfork.org/scripts/440698/([0-9]+)/pvcep_lang.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_lang.js?v=\1#g" \ 25 | "Picviewer CE+/Picviewer CE+.user.js" > "Picviewer CE+/dist.user.js" 26 | 27 | - name: Commit and push dist.user.js 28 | run: | 29 | git config --local user.email "rixixi@gmail.com" 30 | git config --local user.name "hoothin-update" 31 | git add "Picviewer CE+/dist.user.js" 32 | git commit -m "chore(Picviewer CE+): Auto-generate dist.user.js" 33 | git push https://${{ secrets.ACTION_SECRET }}@github.com/${{ github.repository }} 34 | -------------------------------------------------------------------------------- /Switch Traditional Chinese and Simplified Chinese/README.md: -------------------------------------------------------------------------------- 1 | 簡介 2 | --- 3 | 4 | + 預設會自動切換至使用者所使用的語言。 5 | + 按下 `Ctrl + F8` 可在簡體中文與繁體中文之間切換(如果輸入框為活動控制項,則只有輸入框內的文字會被轉換;選取文字時,只有對應的文字會被轉換,且不會被記憶)。 6 | + 使用命令選單中的「繁簡切換【Ctrl + F8】」功能可在當前網域禁用轉換。 7 | + 切換語言後,會儲存目前網站的語言選擇。 8 | + 可轉換頁面中所有的文字內容、描述字元、提示文字、標題等。 9 | + 支援在漢字上方顯示對應的漢語拼音字母。 10 | + 支援彈幕,以及動態插入的元素。 11 | + 可自訂用語轉換詞典。 12 | + 可透過通配符自訂生效網址,以在不同網域套用不同的用語詞典。 13 | 14 | 客制化 15 | --- 16 | 17 | [**Ch'ü Tsê-t'ien 的簡繁用語轉換配置文件**](https://hoothin.github.io/UserScripts/Switch%20Traditional%20Chinese%20and%20Simplified%20Chinese/%E7%B0%A1%E7%B9%81%E8%BD%89%E6%8F%9B%20by%20Ch'%C3%BC%20Ts%C3%AA-t'ien.json) 下載此檔案后在`自訂簡繁用語轉換`旁點擊按鈕匯入即可 18 | 19 | 我建立了一個 sc2tc 陣列,其中包含了簡體中文到繁體中文的對照表。有興趣的朋友可以修改並分享至[GITHUB](https://github.com/hoothin/UserScripts/blob/master/Switch%20Traditional%20Chinese%20and%20Simplified%20Chinese/Switch%20Traditional%20Chinese%20and%20Simplified%20Chinese.user.js)。 20 | 21 | 如果你只是有更好的繁簡對照表,也歡迎提交給我。 22 | 23 | 例如: 24 |
'恶':[
25 |      '惡',
26 |     ['噁','恶心'],
27 |     ['噁','心恶','恶心心']
28 | ],
29 | 第一個 “恶” 是簡體字,第二個 “惡” 是默認轉換的正體字。
接下來是一個或者數個陣列,指向這個簡體對應的其他正體字。
陣列第一位為正體字字元,後面則是對應的簡體應用詞匯。 30 |

31 | 以及一個用語轉換陣列。 32 | 33 | 例如: 34 |
'鼠标':'滑鼠'
35 | 
36 | 37 | 漢語拼音標注 38 | --- 39 | 40 | 目前有個問題,除了配對到詞組的多音字之外,多音單字還需要一個預設拼音。 41 | 42 | 例如“了”應該預設是“le”而不是“liao”。 43 | 44 | 我改了一些,常用的幾個多音單字都改了。但我數了一下,這類多音單字總共有800多個,需要有人來幫忙整理一下。 45 | 46 | 如果有對幫忙有興趣的朋友,以下是整理步驟: 47 | 48 | + 下載dict.txt 49 | + 正規搜尋`^(\S \S) \[.*\n(\1.*\n)+` 50 | + 刪除多餘的行,只保留一個預設讀音 51 | + 將修改後的字典提交給我,也可以直接執行專案中的 run.py 來轉換檔案後查看效果 52 | 53 | npm 前端庫 54 | --- 55 | 56 | ``` 57 | npm install switch-chinese 58 | ``` 59 | 60 | [訪問位址](lib) 61 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Collect wedata for pagetual 2 | 3 | on: 4 | schedule: 5 | - cron: '0 1 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | # This workflow contains a single job called "build" 10 | build: 11 | # The type of runner that the job will run on 12 | runs-on: ubuntu-latest 13 | 14 | # Steps represent a sequence of tasks that will be executed as part of the job 15 | steps: 16 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 17 | - uses: actions/checkout@v2 18 | 19 | #- name: Download json 20 | # run: | 21 | # wget --no-cache -O "Pagetual/items_all.json" http://wedata.net/databases/AutoPagerize/items_all.json 22 | 23 | #- uses: technote-space/get-diff-action@v6 24 | # with: 25 | # FILES: | 26 | # items_all.json 27 | 28 | #- name: Commit 29 | # if: env.GIT_DIFF 30 | # run: | 31 | # git config user.name "github-actions[bot]" 32 | # git config user.email "512946+github-actions[bot]@users.noreply.github.com" 33 | # git add Pagetual/items_all.json 34 | # git status 35 | # git commit -m "auto commit from github actions" 36 | 37 | #- name: Push 38 | # if: env.GIT_DIFF 39 | # uses: ad-m/github-push-action@master 40 | # with: 41 | # github_token: ${{ secrets.GITHUB_TOKEN }} 42 | # branch: master 43 | - name: Update file 44 | id: update_file 45 | uses: TheLastProject/keep-remote-file-locally-up-to-date-action@v1 46 | with: 47 | url: http://wedata.net/databases/AutoPagerize/items_all.json 48 | file_in_repo: Pagetual/items_all.json 49 | git_user: hoothin-update 50 | git_email: rixixi@gmail.com 51 | -------------------------------------------------------------------------------- /Valentine's Day/css/default.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: 'DS-Digital8dbd7695a180ee';src: url('http://cdn.webfont.youziku.com/webfonts/nomal/98542/32780/58a17441f629d815f80ae466.gif');src: url('http://cdn.webfont.youziku.com/webfonts/nomal/98542/32780/58a17441f629d815f80ae466.gif?#iefix') format('embedded-opentype'), url('http://cdn.webfont.youziku.com/webfonts/nomal/98542/32780/58a17441f629d815f80ae466.bmp') format('woff'), url('http://cdn.webfont.youziku.com/webfonts/nomal/98542/32780/58a17441f629d815f80ae466.jpg') format('truetype'), url('http://cdn.webfont.youziku.com/webfonts/nomal/98542/32780/58a17441f629d815f80ae466.png#DS-Digital') format('svg'); }.css8dbd7695a180ee{font-family: 'DS-Digital8dbd7695a180ee';}body{margin:0;padding:0;background:#ffe;font-size:12px;overflow:auto}#mainDiv{width:100%;height:100%}#loveHeart{float:left;width:670px;height:625px}#garden{width:100%;height:100%}#elapseClock{text-align:right;font-size:18px;margin-top:10px;margin-bottom:10px}#words{font-family:"sans-serif";width:500px;font-size:24px;color:#666}#messages{display:none}#elapseClock .digit{font-family:"DS-Digital8dbd7695a180ee";font-size:36px}#loveu{padding:5px;font-size:22px;margin-top:80px;margin-right:120px;text-align:right;display:none}#loveu .signature{margin-top:10px;font-size:20px;font-style:italic}#clickSound{display:none}#code{float:left;width:440px;height:400px;color:#333;font-family:"Consolas","Monaco","Bitstream Vera Sans Mono","Courier New","sans-serif";font-size:12px}#code .string{color:#2a36ff}#code .keyword{color:#7f0055;font-weight:bold}#code .placeholder{margin-left:15px}#code .space{margin-left:7px}#code .comments{color:#3f7f5f}#copyright{margin-top:10px;text-align:center;width:100%;color:#666}#errorMsg{width:100%;text-align:center;font-size:24px;position:absolute;top:100px;left:0}#copyright a{color:#666} -------------------------------------------------------------------------------- /Switch Traditional Chinese and Simplified Chinese/lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "switch-chinese", 3 | "version": "1.0.13", 4 | "description": "繁簡轉換,支援簡繁雙向轉換、智慧分詞、自訂詞庫、文字偵測及多種輸出格式,零依賴。 Lightweight Chinese converter library for conversion between Simplified and Traditional Chinese. 轻量级简繁体中文智能转换库,支持简繁双向转换、智能分词、自定义词库、文本检测及多种输出格式,零依赖。", 5 | "main": "stcasc.lib.js", 6 | "types": "stcasc.d.ts", 7 | "type": "module", 8 | "exports": { 9 | ".": { 10 | "import": "./stcasc.lib.js", 11 | "types": "./stcasc.d.ts" 12 | } 13 | }, 14 | "files": [ 15 | "stcasc.lib.js", 16 | "stcasc.d.ts", 17 | "readme.md" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/hoothin/UserScripts.git#master" 22 | }, 23 | "keywords": [ 24 | "chinese", 25 | "converter", 26 | "traditional", 27 | "simplified", 28 | "chinese-converter", 29 | "simplified-chinese", 30 | "traditional-chinese", 31 | "chinese-translation", 32 | "chinese-detection", 33 | "character-detection", 34 | "text-converter", 35 | "language-converter", 36 | "i18n", 37 | "localization", 38 | "ruby-annotation", 39 | "简繁转换", 40 | "簡繁轉換", 41 | "简繁切换", 42 | "簡繁切換", 43 | "繁简转换", 44 | "繁簡轉換", 45 | "繁简切换", 46 | "繁簡切換", 47 | "简体中文", 48 | "繁体中文", 49 | "簡體中文", 50 | "繁體中文", 51 | "正體中文", 52 | "中文转换", 53 | "中文检测", 54 | "一简多繁", 55 | "智能分词", 56 | "自定义词库", 57 | "零依赖", 58 | "轻量级" 59 | ], 60 | "author": "Hoothin", 61 | "license": "MIT", 62 | "bugs": { 63 | "url": "https://github.com/hoothin/UserScripts/issues" 64 | }, 65 | "homepage": "https://github.com/hoothin/UserScripts/tree/master/Switch%20Traditional%20Chinese%20and%20Simplified%20Chinese/lib", 66 | "engines": { 67 | "node": ">=12.0.0" 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | paths-ignore: 9 | - 'Pagetual/items_all.json' 10 | - 'Pagetual/pagetualRules.json' 11 | - '.github/*' 12 | - '.github/*/*' 13 | workflow_run: 14 | workflows: ["Update Version on File Change"] 15 | types: 16 | - completed 17 | 18 | # Allows you to run this workflow manually from the Actions tab 19 | workflow_dispatch: 20 | 21 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 22 | permissions: 23 | contents: read 24 | pages: write 25 | id-token: write 26 | 27 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 28 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 29 | concurrency: 30 | group: "pages" 31 | cancel-in-progress: false 32 | 33 | jobs: 34 | # Build job 35 | build: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v4 40 | - name: Setup Pages 41 | uses: actions/configure-pages@v5 42 | - name: Build with Jekyll 43 | uses: actions/jekyll-build-pages@v1 44 | with: 45 | source: ./ 46 | destination: ./_site 47 | - name: Upload artifact 48 | uses: actions/upload-pages-artifact@v3 49 | 50 | # Deployment job 51 | deploy: 52 | environment: 53 | name: github-pages 54 | url: ${{ steps.deployment.outputs.page_url }} 55 | runs-on: ubuntu-latest 56 | needs: build 57 | steps: 58 | - name: Deploy to GitHub Pages 59 | id: deployment 60 | uses: actions/deploy-pages@v4 61 | -------------------------------------------------------------------------------- /.github/workflows/update_version.yml: -------------------------------------------------------------------------------- 1 | name: Update Version on File Change 2 | on: 3 | push: 4 | paths: 5 | - 'Pagetual/items_all.json' 6 | - 'Pagetual/pagetualRules.json' 7 | workflow_run: 8 | workflows: ["Collect wedata for pagetual"] 9 | types: 10 | - completed 11 | 12 | jobs: 13 | update_version: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Check file modification timestamps 22 | id: check_file_timestamps 23 | run: | 24 | version_timestamp=$(git log -1 --format="%at" Pagetual/version) 25 | items_all_timestamp=$(git log -1 --format="%at" Pagetual/items_all.json) 26 | pagetualRules_timestamp=$(git log -1 --format="%at" Pagetual/pagetualRules.json) 27 | if [[ $version_timestamp < $items_all_timestamp || $version_timestamp < $pagetualRules_timestamp ]]; then 28 | version=$(cat Pagetual/version) 29 | else 30 | version=0 31 | echo "Version file is not updated. Skipping version read." 32 | fi 33 | echo "VERSION=$version" >> $GITHUB_ENV 34 | 35 | - name: Increment version 36 | if: env.VERSION != '0' 37 | id: increment_version 38 | run: echo "VERSION=$((VERSION + 1))" >> $GITHUB_ENV 39 | 40 | - name: Update version file 41 | if: env.VERSION != '0' 42 | run: echo $VERSION > Pagetual/version 43 | 44 | - name: Commit version update 45 | if: env.VERSION != '0' 46 | run: | 47 | git config --local user.email "rixixi@gmail.com" 48 | git config --local user.name "hoothin-update" 49 | git add Pagetual/version 50 | git commit -m "Update version of Pagetual rules to $VERSION" 51 | git push https://${{ secrets.ACTION_SECRET }}@github.com/${{ github.repository }} 52 | -------------------------------------------------------------------------------- /True URL downloads/README.md: -------------------------------------------------------------------------------- 1 | [[Chrome Batch Download Extension]](https://chrome.google.com/webstore/detail/dbheplacgeefjnhdacijldhfliehnhka) 2 | 3 | Decryption and Display the real URL of the download links and then manage them.(thunder,flashget,qqdl) 4 | 5 | Can cooperate with [[Multi-Select Checkbox Companion]](https://greasyfork.org/scripts/22587) to facilitate checkbox selection 6 | 7 | 8 | Test ALT+X:[MP4](http://a.a/h.mp4) [MP3](http://a.a/o.mp3) [RAR](http://a.a/o.rar) [7Z](http://a.a/t.7z) [ZIP](http://a.a/h.zip) [TXT](http://a.a/i.txt) [PDF](http://a.a/n.pdf) 9 | 10 | 11 | 12 | Download sniffing 13 | 14 | 15 | [![img](https://img.shields.io/github/stars/hoothin/UserScripts?style=social)](https://github.com/hoothin/UserScripts) 16 | Forked from [http://userscripts-mirror.org/scripts/show/157556](http://userscripts-mirror.org/scripts/show/157556 "Xunlei, Express, QQ Tornado dedicated link decoding by yulei") 17 | 18 | 19 | --- 20 | change content 21 | - 22 | + Add batch copy function, which can copy magnetic links, compressed files, videos, music, e-books, torrent files, eMule resources, apk, etc. in the current page for batch download, press **`Alt + x`** or Click **`True url links copy`** in the user script command menu 23 | (You can add the prefix yourself, such as `"aria2c"` to facilitate batch offline download of aria2, you can use %i to represent the incremental number and %n to represent the file name) 24 | 25 | + Link item judgment optimization, exclude non-proprietary link items such as thunder: 26 | 27 | + Hold **`CTRL`** to decipher the private chain 28 | 29 | + Right click to decrypt the link to reset the bug fix 30 | 31 | + Fix the Chinese garbled problem of some websites, for example: http://www.80s.tw/movie/18912 32 | 33 | + Based on performance considerations, lock for 0.5 seconds after page change detection is triggered 34 | 35 | + Other modifications and optimizations 36 | -------------------------------------------------------------------------------- /Bilibili Bangumi Cover/Bilibili Bangumi Cover.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Bilibili Bangumi Cover 3 | // @name:zh-CN 哔哩哔哩番剧封面 4 | // @namespace hoothin 5 | // @version 0.7 6 | // @description Show Bilibili Bangumi Cover 7 | // @description:zh-CN 在哔哩哔哩番剧页面中显示封面 8 | // @grant GM_xmlhttpRequest 9 | // @author hoothin 10 | // @include http*://bangumi.bilibili.com/anime/* 11 | // @include http*://www.bilibili.com/bangumi/play/* 12 | // ==/UserScript== 13 | 14 | (function() { 15 | 'use strict'; 16 | var vSmall=document.querySelector(".bangumi-recom"); 17 | console.log(vSmall); 18 | if(!vSmall)return; 19 | var title=document.createElement("h4"); 20 | title.id="coverTitle"; 21 | title.classList.add("recom-title"); 22 | title.style.display="block"; 23 | title.innerHTML="封面"; 24 | var coverLink=document.createElement("a"); 25 | var cover=document.createElement("img"); 26 | cover.style.width="270px"; 27 | coverLink.target="_blank"; 28 | coverLink.appendChild(cover); 29 | /*var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 30 | var observer = new MutationObserver(function(records){ 31 | }); 32 | var option = { 33 | 'childList': true 34 | }; 35 | observer.observe(vSmall, option);*/ 36 | if(!vSmall.querySelector("h3#coverTitle")){ 37 | vSmall.insertBefore(coverLink,vSmall.firstChild); 38 | vSmall.insertBefore(title,vSmall.firstChild); 39 | refreshCover(); 40 | } 41 | function refreshCover(){ 42 | GM_xmlhttpRequest({ 43 | method: 'GET', 44 | url: "http://bangumi.bilibili.com/web_api/episode/"+location.href.replace(/.*ep/i,"")+".json", 45 | onload: function(result) { 46 | console.log(11); 47 | try { 48 | var bangumiData = JSON.parse(result.responseText); 49 | coverLink.href=cover.src=bangumiData.result.currentEpisode.cover; 50 | }catch (e) { 51 | console.log(e); 52 | } 53 | } 54 | }); 55 | } 56 | })(); -------------------------------------------------------------------------------- /HacgGodTurn/README.md: -------------------------------------------------------------------------------- 1 | 琉璃神社与其他绅士站神秘代码转换成下载链接 2 | ========================== 3 | 主要功能:转换各绅士站的神秘代码,嗅探下载链接,去除和谐限制,快速翻页、定位或访问文章 4 | 5 | [**浏览器必须支持ES6**](https://www.hacg.fi/wp/) 6 | 7 | ![img](https://sleazyfork.org/system/screenshots/screenshots/000/005/554/original/GIF.gif) 8 | 9 | --- 10 | 详细说明 11 | --- 12 | + 增加支持如下Hentai站: 13 | - [灵梦御所](https://blog.reimu.net/ "porn 8")、[纯爱计划](https://sexacg.com/ "挊")、[绅士二次元](https://www.acg.tf/ "上车")、[萌心次元](https://www.moxacg.com/ "1024")、[次元轨迹](https://www.acggj.com/ "拤")、[ACG调查小队](https://acg12.com/ "老司机")、[幻天领域](https://www.acgnz.cc/)、[轻萌社](http://nacg.me/ "撸")、[紳士の庭](https://gmgard.com/ "传说")、[我的Galgame资源发布站](https://www.mygalgame.com/)、[天使二次元](https://www.tianshit.com/)、[樱花漫舍](https://www.oomoe.moe/)、[风铃窝](http://www.kaze5.com/)、[次元の圣光](http://www.acglover.top/)、[爱弹幕](http://www.idanmu.co/)、[幻想次元](https://acg18.us/)、[司机会所](http://www.sijihuisuo.club/)、[里番萌](https://lifanmoe.com/)、[最ACG](http://zuiacg.com/)、[绅士仓库](http://www.galacg.me/)、[梦幻二次元](http://www.mhecy.com/)、[ACG和谐区/里世界](http://acgzone.org/)、[寂月神社](https://acgmoon.org/)、[萌幻之乡](https://www.moe-acg.cc/) 14 | 其他的`Alt`+`F8`查看 15 | 16 | + 通用快捷键: 17 | - `F8`或者`shift`+`F8`向前或向后循环宅站列表 18 | - `← →`快速定位到上一篇或下一篇文章 19 | - `Ctrl`+`← →`快速翻页 20 | - `Ctrl`+`↑ ↓`进入文章内容页或返回 21 | - `Alt`+`F8`打开绅士站点列表 22 | - `Ctrl`+`F8`打开火箭嗅探窗口(这样就可以`Ctrl`+` →`、`Ctrl`+`F8`快速查找评论里的资源啦) 23 | 24 | + 最ACG快捷键: 25 | - 点击图片去除和谐力量 26 | - 按住`Ctrl`点击图集或文章页面的下载按钮直接跳转至百度盘 27 | 28 | + 火箭功能,一键嗅探所有下载链接,点击序号定位至页面中资源所在位置 29 | 30 | + 老司机输入框输入`链接:https://pan.baidu.com/s/11111111 密码:2222`或者`11111111 2222`等可跳转至`https://pan.baidu.com/s/11111111#2222` 31 | 32 | + 绅士站点各种神秘代码转换成下载链接 33 | 34 | + 爱弹幕添加R18福利tag并去除和谐图片屏蔽 35 | 36 | + 替换神社所有http链接为https,免翻墻 37 | 38 | + 绅士二次元自动解密AES 39 | 40 | + 司机会所评论区分享地址解析 41 | 42 | + 寂月神社和谐内容可视切换按钮 43 | 44 | + 萌心次元、次元轨迹、里番萌、幻天领域与ACG调查小队无法访问时自动转https,坑爹的移动网(部分站点https支持不完全,转https后无法登录) 45 | 46 | + 次元轨迹添加三次元tag 47 | 48 | + 我的Galgame资源发布站MyGalgame顶端添加当前背景图片链接 49 | 50 | + 增强度盘支持,文字转链接,自动填写提取码 51 | 52 | + 次元轨迹、樱花漫舍、风铃窝、萌幻之乡与ACG调查小队自动添加提取码 53 | 54 | + 修复7酱8酱9酱A君B君Q君等等提取码 55 | 56 | + 修复折叠失效问题 57 | 58 | + 增加32位md5磁链支持 59 | 60 | + 磁链判断优化 61 | 62 | + 重构啦,删除了之前写的一些冗余代码 63 | 64 | + 御所某些家伙深深伤害了我的狗眼,所以加了个“好孩子看不见”的按钮,点击之后才会显示隐藏内容 65 | 66 | + 幻想次元看不到图需要在adb里加一条规则(`@@||sinaimg.cn^$domain=acg18.us`) 67 | 68 | --- 69 | 加了太多东西,其他的修改内容懒得记了 -------------------------------------------------------------------------------- /Anti-anti-pic-stealing-link/Anti-anti-pic-stealing-link.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 反图片防盗链 3 | // @name:en Anti-anti-pic-stealing-link 4 | // @namespace hoothin 5 | // @version 0.3 6 | // @description 破解图片防盗链 7 | // @description:en crack Anti-pic-stealing-link to show real picture 8 | // @author hoothin 9 | // @include http*://*/* 10 | // @grant unsafeWindow 11 | // @grant GM_registerMenuCommand 12 | // @grant GM_getValue 13 | // @grant GM_setValue 14 | // ==/UserScript== 15 | 16 | (function() { 17 | 'use strict'; 18 | const sites={ 19 | "qq.com": "photo\.store\.qq\.com", 20 | "baidu.com": "a\.hiphotos\.baidu\.com\/image", 21 | }; 22 | var customRule=GM_getValue("aaslr"); 23 | function refererChanger(item){ 24 | var frameid = 'frameimg' + Math.random(); 25 | unsafeWindow.img = ''; 26 | var iframe=document.createElement("iframe"); 27 | iframe.id=frameid; 28 | iframe.src="javascript:parent.img;"; 29 | iframe.frameBorder="0"; 30 | iframe.scrolling="no"; 31 | iframe.width="100%"; 32 | item.parentNode.replaceChild(iframe,item); 33 | } 34 | GM_registerMenuCommand("Anti-anti-pic-stealing-link rule", function(){ 35 | var input=prompt("Set up Anti-anti-pic-stealing-link rule:",customRule?customRule:"photo\.store\.qq\.com"); 36 | //if(input){ 37 | customRule=input; 38 | GM_setValue("aaslr",customRule); 39 | //} 40 | }); 41 | [].forEach.call(document.querySelectorAll("img"),function(item){ 42 | for (var i in sites) { 43 | var sitePatt=new RegExp(sites[i],"i"); 44 | if(sitePatt.test(item.src)){ 45 | if(!(new RegExp(i,"i")).test(location.hostname)){ 46 | refererChanger(item); 47 | } 48 | break; 49 | } 50 | } 51 | if(customRule && (new RegExp(customRule,"i")).test(item.src)){ 52 | refererChanger(item); 53 | } 54 | }); 55 | })(); 56 | -------------------------------------------------------------------------------- /Appinn Comment/AppinnComment.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Appinn comment 3 | // @name:zh-CN 小众软件评论显示 4 | // @namespace hoothin 5 | // @version 2024-06-08 6 | // @description Display the comments from the Appinn forum on the bottom of the corresponding page on the main site. 7 | // @description:zh-CN 将小众软件论坛的评论内容显示在主站对应页面下部 8 | // @author hoothin 9 | // @match https://www.appinn.com/* 10 | // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 11 | // @grant GM_xmlhttpRequest 12 | // @connect meta.appinn.net 13 | // @downloadURL https://update.greasyfork.org/scripts/497293/Appinn%20comment.user.js 14 | // @updateURL https://update.greasyfork.org/scripts/497293/Appinn%20comment.meta.js 15 | // ==/UserScript== 16 | 17 | (function() { 18 | 'use strict'; 19 | const commentLink = document.querySelector('a.wpdc-join-discussion-link'); 20 | if (!commentLink) return; 21 | GM_xmlhttpRequest({ 22 | url: commentLink.href, 23 | method: 'GET', 24 | onload: function(res) { 25 | try { 26 | let doc = document.implementation.createHTMLDocument(''); 27 | doc.documentElement.innerHTML = res.response; 28 | let dataPreloaded = doc.getElementById('data-preloaded'); 29 | if (!dataPreloaded) return; 30 | dataPreloaded = JSON.parse(JSON.parse(dataPreloaded.dataset.preloaded)["topic_" + commentLink.href.match(/\d+/)[0]]).post_stream.posts; 31 | let posts = document.createElement("ul"); 32 | posts.style.maxHeight = '90vh'; 33 | posts.style.overflow = 'auto'; 34 | posts.style.margin = '0'; 35 | let title = document.createElement("h3"); 36 | title.innerText = "评论内容"; 37 | document.querySelector('article').appendChild(title); 38 | document.querySelector('article').appendChild(posts); 39 | dataPreloaded.forEach(item => { 40 | posts.innerHTML += `
  • ${item.display_username || item.username}

    ${item.cooked}
  • `; 41 | }); 42 | } catch (e) { 43 | } 44 | } 45 | }); 46 | })(); -------------------------------------------------------------------------------- /Disable AD of ThisAV/Disable AD of ThisAV.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name ThisAV去广告 3 | // @name:en Disable AD of ThisAV 4 | // @name:zh-TW ThisAV去廣告 5 | // @namespace hoothin 6 | // @version 0.62 7 | // @description 去除ThisAV页面中的弹出广告与导航栏广告,添加视频下载按钮 8 | // @description:en Just disable popup AD & tab menu AD of ThisAV.com 9 | // @description:zh-TW 去除ThisAV頁面中的彈出廣告與導航欄廣告,添加視頻下載按鈕 10 | // @author hoothin 11 | // @include http*://thisav.com/* 12 | // @include http*://www.thisav.com/* 13 | // @grant unsafeWindow 14 | // ==/UserScript== 15 | 16 | (function() { 17 | 'use strict'; 18 | var _unsafeWindow=(typeof unsafeWindow=='undefined')?window:unsafeWindow; 19 | document.onclick=null; 20 | var tabsmenus=document.querySelectorAll("#slidetabsmenu>ul>li>a"); 21 | for(var i=0;i 5: 47 | continue; 48 | elif (tone == 5): 49 | syllables[i] = syllable[:len(syllable) - 1]; 50 | else: 51 | for j in range(0, len(syllable)): 52 | currentLetter = syllable[j].lower(); 53 | 54 | if replacements.get(currentLetter, "") != "": 55 | nextLetter = syllable[j + 1]; 56 | letterToReplace = ""; 57 | 58 | if replacements.get(nextLetter, "") != "" and currentLetter in medials: 59 | letterToReplace = nextLetter; 60 | else: 61 | letterToReplace = currentLetter; 62 | 63 | replaced = syllable.replace(letterToReplace, replacements[letterToReplace][tone - 1]); 64 | syllables[i] = replaced[0: len(replaced) - 1]; 65 | break; 66 | return " ".join(syllables); 67 | 68 | def main(): 69 | data = [] 70 | print("Reading input file") 71 | runtimes = 0 72 | with open(inputFile, 'r', encoding = 'utf-8') as txtfile: 73 | for line in txtfile: 74 | matchObject = re.match(r'(\S+) (\S+) \[(.*)\]', line, re.I) 75 | traditional = matchObject.group(1) 76 | simplified = matchObject.group(2) 77 | pinyin = prettify(matchObject.group(3)) 78 | add_to_dict(tree, simplified, pinyin) 79 | add_to_dict(tree, traditional, pinyin) 80 | 81 | with open(outputFile, 'w', encoding='utf-8') as f: 82 | json.dump(tree, f, ensure_ascii=False) 83 | 84 | if __name__ == '__main__': 85 | main() -------------------------------------------------------------------------------- /Valentine's Day/js/functions.js: -------------------------------------------------------------------------------- 1 | var $window=$(window),gardenCtx,gardenCanvas,$garden,garden;var clientWidth=$(window).width();var clientHeight=$(window).height();$(function(){$loveHeart=$("#loveHeart");var a=$loveHeart.width()/2;var b=$loveHeart.height()/2-55;$garden=$("#garden");gardenCanvas=$garden[0];gardenCanvas.width=$("#loveHeart").width();gardenCanvas.height=$("#loveHeart").height();gardenCtx=gardenCanvas.getContext("2d");gardenCtx.globalCompositeOperation="lighter";garden=new Garden(gardenCtx,gardenCanvas);$("#content").css("width",$loveHeart.width()+$("#code").width());$("#content").css("height",Math.max($loveHeart.height(),$("#code").height()));$("#content").css("margin-top",Math.max(($window.height()-$("#content").height())/2,10));$("#content").css("margin-left",Math.max(($window.width()-$("#content").width())/2,10));setInterval(function(){garden.render()},Garden.options.growSpeed)});$(window).resize(function(){var b=$(window).width();var a=$(window).height();if(b!=clientWidth&&a!=clientHeight){location.replace(location)}});function getHeartPoint(c){var b=c/Math.PI;var a=19.5*(16*Math.pow(Math.sin(b),3));var d=-20*(13*Math.cos(b)-5*Math.cos(2*b)-2*Math.cos(3*b)-Math.cos(4*b));return new Array(offsetX+a,offsetY+d)}function startHeartAnimation(){var c=50;var d=10;var b=new Array();var a=setInterval(function(){var h=getHeartPoint(d);var e=true;for(var f=0;f=30){clearInterval(a);showMessages()}else{d+=0.2}},c)}(function(a){a.fn.typewriter=function(){this.each(function(){var d=a(this),c=d.html(),b=0;d.html("");var e=setInterval(function(){var f=c.substr(b,1);if(f=="<"){b=c.indexOf(">",b)+1}else{b++}d.html(c.substring(0,b)+(b&1?"_":""));if(b>=c.length){clearInterval(e)}},75)});return this}})(jQuery);function timeElapse(c){var e=Date();var f=(Date.parse(e)-Date.parse(c))/1000;var g=Math.floor(f/(3600*24));f=f%(3600*24);var b=Math.floor(f/3600);if(b<10){b="0"+b}f=f%3600;var d=Math.floor(f/60);if(d<10){d="0"+d}f=f%60;if(f<10){f="0"+f}var a=''+g+' days '+b+' hours '+d+' minutes '+f+" seconds";$("#elapseClock").html(a)}function showMessages(){adjustWordsPosition();$("#messages").fadeIn(5000,function(){showLoveU()})}function adjustWordsPosition(){$("#words").css("position","absolute");$("#words").css("top",$("#garden").position().top+195);$("#words").css("left",$("#garden").position().left+70)}function adjustCodePosition(){$("#code").css("margin-top",($("#garden").height()-$("#code").height())/2)}function showLoveU(){$("#loveu").fadeIn(3000)}; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

    ⚙️Greasemonkey scripts

    2 | 3 |

    4 | license 5 | Support 6 | Contact 7 |

    8 | 9 | --- 10 | 11 | + [Pagetual · 東方永頁機](https://pagetual.hoothin.com/ "Auto pager script to fetch next page automatically for infinity scroll. Pagetual 東方永頁機 东方永页机") [![](https://img.shields.io/greasyfork/dd/438684)](Pagetual) 12 | 13 | + [SearchJumper · 搜尋醬](https://search.hoothin.com/ "Conduct searches for selected text/image effortlessly. Navigate to any search engine(Google/Bing/Custom) swiftly. SearchJumper 搜索酱 搜尋醬") [![](https://img.shields.io/greasyfork/dd/445274)](https://github.com/hoothin/SearchJumper) 14 | 15 | + [Easy offline · 一鍵離綫下載 ![](https://img.shields.io/greasyfork/dt/22590)](Easy%20offline "Find out all magnet links and torrents and video links in current page, and stream them from cloud storage automatically.") 16 | 17 | + [Picviewer CE+](Picviewer%20CE%2B "Powerful picture viewing tool online, which can popup/scale/rotate/batch save pictures automatically.") [![](https://img.shields.io/greasyfork/dd/24204)](Picviewer%20CE%2B) 18 | 19 | + [Switch Traditional Chinese and Simplified Chinese · 簡繁自由切換 ![](https://img.shields.io/greasyfork/dt/24300)](Switch%20Traditional%20Chinese%20and%20Simplified%20Chinese "Convert between simplified and traditional Chinese characters on any webpage, display the Pinyin for the Chinese characters, customize text replacement.") 20 | 21 | + [Greasyfork Search with Sleazyfork Results include · 大人的Greasyfork ![](https://img.shields.io/greasyfork/dt/23840)](Greasyfork%20Search%20with%20Sleazyfork%20Results%20include "Merge adult results of sleazyfork into greasyfork when the script is no longer anonymously available, add rating score and version for scripts then.") 22 | 23 | + [DownloadAllContent · 怠惰小說下載器](DownloadAllContent "Lightweight web scraping script. Fetch and download main textual content from the current page, provide special support for novels.") [![](https://img.shields.io/greasyfork/dd/25068)](DownloadAllContent) 24 | 25 | + [HGT Decode · 琉神轉 ![](https://img.shields.io/greasyfork/dt/23316)](HacgGodTurn) 26 | 27 | + [Select All Checkboxes · 多選框伴侶 ![](https://img.shields.io/greasyfork/dt/22587)](Select%20All%20Checkboxes) 28 | 29 | + [MoreSteamRatings · Steam遊戲評分集 ![](https://img.shields.io/greasyfork/dt/24113)](MoreSteamRatings) 30 | 31 | + [Highlight Every Code · 程式碼片段高亮 ![](https://img.shields.io/greasyfork/dt/24150)](Highlight%20Every%20Code) 32 | 33 | + [True URL downloads ![](https://img.shields.io/greasyfork/dt/7362)](True%20URL%20downloads) 34 | 35 | + [JandanHero · 煎蛋俠 ![](https://img.shields.io/greasyfork/dt/25597)](JiandanHero) 36 | 37 | ## Contributors 38 | 39 | 40 | 41 | 42 | 43 | ## Star History 44 | 45 | [![Star History Chart](https://api.star-history.com/svg?repos=hoothin/UserScripts&type=Date)](https://star-history.com/#hoothin/UserScripts&Date) 46 | -------------------------------------------------------------------------------- /Valentine's Day/js/garden.js: -------------------------------------------------------------------------------- 1 | function Vector(a,b){this.x=a;this.y=b}Vector.prototype={rotate:function(b){var a=this.x;var c=this.y;this.x=Math.cos(b)*a-Math.sin(b)*c;this.y=Math.sin(b)*a+Math.cos(b)*c;return this},mult:function(a){this.x*=a;this.y*=a;return this},clone:function(){return new Vector(this.x,this.y)},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},subtract:function(a){this.x-=a.x;this.y-=a.y;return this},set:function(a,b){this.x=a;this.y=b;return this}};function Petal(a,f,b,e,c,d){this.stretchA=a;this.stretchB=f;this.startAngle=b;this.angle=e;this.bloom=d;this.growFactor=c;this.r=1;this.isfinished=false}Petal.prototype={draw:function(){var a=this.bloom.garden.ctx;var e,d,c,b;e=new Vector(0,this.r).rotate(Garden.degrad(this.startAngle));d=e.clone().rotate(Garden.degrad(this.angle));c=e.clone().mult(this.stretchA);b=d.clone().mult(this.stretchB);a.strokeStyle=this.bloom.c;a.beginPath();a.moveTo(e.x,e.y);a.bezierCurveTo(c.x,c.y,b.x,b.y,d.x,d.y);a.stroke()},render:function(){if(this.r<=this.bloom.r){this.r+=this.growFactor;this.draw()}else{this.isfinished=true}}};function Bloom(e,d,f,a,b){this.p=e;this.r=d;this.c=f;this.pc=a;this.petals=[];this.garden=b;this.init();this.garden.addBloom(this)}Bloom.prototype={draw:function(){var c,b=true;this.garden.ctx.save();this.garden.ctx.translate(this.p.x,this.p.y);for(var a=0;a Array(a.length + 1).fill(null)); 23 | //第一行 24 | for (let i = 0; i <= a.length; i += 1) { 25 | distanceMatrix[0][i] = i; 26 | } 27 | //第一列 28 | for (let j = 0; j <= b.length; j += 1) { 29 | distanceMatrix[j][0] = j; 30 | } 31 | for (let j = 1; j <= b.length; j += 1) { 32 | for (let i = 1; i <= a.length; i += 1) { 33 | const indicator = a[i - 1] === b[j - 1] ? 0 : 1; 34 | distanceMatrix[j][i] = Math.min( 35 | distanceMatrix[j][i - 1] + 1, // 前一個,增加位數,必須加一 36 | distanceMatrix[j - 1][i] + 1, // 上一個,增加位數,必須加一 37 | distanceMatrix[j - 1][i - 1] + indicator, // 斜方向一個,位數不變 38 | ); 39 | } 40 | } 41 | return distanceMatrix[b.length][a.length]; 42 | } 43 | const gapStr = "[\n\/\\'\"‘’“”,.!\?,。!?…\(\) ]"; 44 | const gapStrs = new RegExp(gapStr + "+", "g"); 45 | _unsafeWindow.searchJumperAddons.push({ 46 | name: "Levenshtein", 47 | type: "findInPage", 48 | sort: 0, 49 | run: (text, keywords) => { 50 | if (!text || !keywords) return {matched: false}; 51 | if (keywords.charCodeAt(0) > 255) { 52 | let len = keywords.length; 53 | let pos = text.toUpperCase().indexOf(keywords.toUpperCase()); 54 | return {matched: pos != -1, pos: pos, len: len}; 55 | } 56 | text = text.toLowerCase(); 57 | keywords = keywords.toLowerCase(); 58 | let wordArr = text.replace(gapStrs, " ").split(" "); 59 | let kwArr = keywords.replace(gapStrs, " ").split(" "); 60 | let matched = false, pos = -1, len = 0, matchedStr = []; 61 | for (let i = 0; i < wordArr.length; i++) { 62 | matched = true; 63 | matchedStr = []; 64 | for (let j = 0; j < kwArr.length; j++) { 65 | let kwLen = kwArr[j].length; 66 | let maxTolerance = kwLen>>2; 67 | if (kwLen > 3) maxTolerance++; 68 | if (!wordArr[i + j] || levenshteinDistance(kwArr[j], wordArr[i + j]) > maxTolerance) { 69 | matched = false; 70 | break; 71 | } else { 72 | matchedStr.push(wordArr[i + j].replace(/([\[\]\(\)\^\$\.\+\*\?\|\{\}\-])/g, "\\$1")); 73 | } 74 | } 75 | if (matched) { 76 | break; 77 | } 78 | } 79 | if (matched) { 80 | let wordMatch = text.match(new RegExp(`(\\b|\\s)(` + matchedStr.join(gapStr + "+") + `)(\\b|\\s)`, "i")); 81 | if (wordMatch) { 82 | let content = wordMatch[2]; 83 | len = content.length; 84 | pos = wordMatch.index + wordMatch[1].length; 85 | } 86 | } 87 | return {matched: matched, pos: pos, len: len}; 88 | } 89 | }); 90 | })(); -------------------------------------------------------------------------------- /Select All Checkboxes/Select All Checkboxes.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Select All Checkboxes 3 | // @name:zh-CN 多选框伴侣 4 | // @name:zh-TW 多選框伴侶 5 | // @namespace hoothin 6 | // @version 0.6.2 7 | // @description A mate for checkbox, select all checkboxes by press Ctrl+Alt+mouse1, or select checkboxes with mouse over by press Alt, or select checkboxes between 2 marks by press Shift. 8 | // @description:zh-CN Ctrl+Alt点击全选多选框,Alt加鼠标悬停选择多选框,Shift选择两个多选框之间的所有多选框 9 | // @description:zh-TW Ctrl+Alt點擊全選多選框,Alt加鼠標懸停選擇多選框,Shift選擇兩個多選框之間的所有多選框 10 | // @author Hoothin 11 | // @include http*://*/* 12 | // @require https://unpkg.com/jquery@3.7.1/dist/jquery.min.js 13 | // @grant GM_registerMenuCommand 14 | // @grant GM.registerMenuCommand 15 | // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=rixixi@sina.com&item_name=Greasy+Fork+donation 16 | // @contributionAmount 1 17 | // ==/UserScript== 18 | 19 | (function() { 20 | 'use strict'; 21 | var type=navigator.appName; 22 | var lang = null; 23 | if (type=="Netscape"){ 24 | lang = navigator.language; 25 | }else{ 26 | lang = navigator.userLanguage; 27 | } 28 | var langStr = lang.substr(0,2); 29 | if (langStr == "zh"){ 30 | langStr = "全选"; 31 | }else{ 32 | langStr = "SelectAll"; 33 | } 34 | var _GM_registerMenuCommand; 35 | if(typeof GM_registerMenuCommand!='undefined'){ 36 | _GM_registerMenuCommand=GM_registerMenuCommand; 37 | }else if(typeof GM!='undefined' && typeof GM.registerMenuCommand!='undefined'){ 38 | _GM_registerMenuCommand=GM.registerMenuCommand; 39 | } 40 | if(typeof _GM_registerMenuCommand=='undefined')_GM_registerMenuCommand=(s,f)=>{}; 41 | _GM_registerMenuCommand(langStr, selectAll); 42 | var selector="input:checkbox:enabled,.checkbox"; 43 | 44 | function selectAll(){ 45 | $(selector).click(); 46 | } 47 | 48 | var preObj; 49 | var mouseDownHandler = function (event) { 50 | let self = this, doc = document; 51 | if (this.shadowRoot && this.shadowRoot.activeElement) { 52 | if (this.shadowRoot.activeElement.type != "checkbox" || !/^input$/i.test(this.shadowRoot.activeElement.nodeName)) { 53 | return; 54 | } else { 55 | self = this.shadowRoot.activeElement; 56 | doc = this.shadowRoot; 57 | } 58 | } 59 | if(!event.shiftKey&&event.altKey&&event.ctrlKey){ 60 | $(selector, doc).click(); 61 | self.click(); 62 | }else if(event.shiftKey&&!event.altKey&&!event.ctrlKey){ 63 | var curParent=self; 64 | var preParent=preObj; 65 | for(var i=0;i<5;i++){ 66 | curParent=curParent.parentNode; 67 | preParent=preParent.parentNode; 68 | if(!curParent||!preParent) { 69 | preObj=self; 70 | return; 71 | } 72 | if(curParent==preParent){ 73 | var target=self; 74 | var find=false; 75 | $(curParent).find(selector).each(function(){ 76 | if(this==preObj||this==target){ 77 | if(find){ 78 | find=false; 79 | return; 80 | } 81 | find=true; 82 | }else if(find){ 83 | this.click(); 84 | } 85 | }); 86 | break; 87 | } 88 | } 89 | } 90 | preObj=self; 91 | }; 92 | var mouseEnterHandler = function (event) { 93 | if(!event.shiftKey&&event.altKey&&!event.ctrlKey){ 94 | this.click(); 95 | } 96 | }; 97 | $(document).on("mousedown", selector, mouseDownHandler); 98 | $(document).on("mouseup", "#download-all-content", mouseDownHandler); 99 | $(document).on("mouseenter", selector, mouseEnterHandler); 100 | })(); -------------------------------------------------------------------------------- /Picviewer CE+/pvcep_pdf_addon.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Picviewer CE+ PDF addon 3 | // @name:zh-CN Picviewer CE+ PDF 扩展 4 | // @name:zh-TW Picviewer CE+ PDF 擴充 5 | // @namespace https://github.com/hoothin/UserScripts 6 | // @version 2024-06-29 7 | // @description Batch Download as PDF instead of ZIP 8 | // @description:zh-CN 取代 ZIP, 打包下载时下载为 PDF 9 | // @description:zh-TW 取代 ZIP, 打包下載時下載為 PDF 10 | // @author hoothin 11 | // @match *://*/* 12 | // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAV1BMVEUAAAD////29vbKysoqKioiIiKysrKhoaGTk5N9fX3z8/Pv7+/r6+vk5OTb29vOzs6Ojo5UVFQzMzMZGRkREREMDAy4uLisrKylpaV4eHhkZGRPT08/Pz/IfxjQAAAAgklEQVQoz53RRw7DIBBAUb5pxr2m3/+ckfDImwyJlL9DDzQgDIUMRu1vWOxTBdeM+onApENF0qHjpkOk2VTwLVEF40Kbfj1wK8AVu2pQA1aBBYDHJ1wy9Cf4cXD5chzNAvsAnc8TjoLAhIzsBao9w1rlVTIvkOYMd9nm6xPi168t9AYkbANdajpjcwAAAABJRU5ErkJggg== 13 | // @grant unsafeWindow 14 | // @grant GM_registerMenuCommand 15 | // @grant GM_unregisterMenuCommand 16 | // @grant GM_getValue 17 | // @grant GM_setValue 18 | // @require https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js 19 | // ==/UserScript== 20 | 21 | (function() { 22 | 'use strict'; 23 | async function blobToDataURL(blob) { 24 | return new Promise((resolve) => { 25 | setTimeout(() => { 26 | var a = new FileReader(); 27 | a.readAsDataURL(blob); 28 | a.onload = function (e) { 29 | resolve(e.target.result); 30 | }; 31 | a.onerror = function (e) { 32 | resolve(null); 33 | }; 34 | }, 0); 35 | }); 36 | } 37 | 38 | function img2pdf(pdfName) { 39 | if (!(this instanceof img2pdf)) { 40 | return new img2pdf(); 41 | } 42 | this.fileList = []; 43 | this.file = async (fileName, blob) => { 44 | this.fileList.push([fileName, blob]); 45 | }; 46 | this.generateAsync = async (config, progress) => { 47 | const pdf = new window.jspdf.jsPDF(); 48 | const fileLength = this.fileList.length; 49 | for (const [key, param] of this.fileList.entries()) { 50 | let fileName = param[0]; 51 | let blob = param[1]; 52 | if (!blob && this.fileList.length === 1) { 53 | fileName = this.fileList[0][0]; 54 | blob = this.fileList[0][1]; 55 | } 56 | try { 57 | let dataUrl = await blobToDataURL(blob); 58 | const imgProps = pdf.getImageProperties(dataUrl); 59 | const imgWidth = pdf.internal.pageSize.getWidth(); 60 | const pageHeight = pdf.internal.pageSize.getHeight(); 61 | const imgHeight = imgProps.height * imgWidth / imgProps.width; 62 | let heightLeft = imgHeight; 63 | let position = 0; 64 | 65 | pdf.addImage(dataUrl, blob.type, 0, position, imgWidth, imgHeight); 66 | heightLeft -= pageHeight; 67 | 68 | while (heightLeft >= 0) { 69 | position -= pageHeight; 70 | pdf.addPage(); 71 | pdf.addImage(dataUrl, blob.type, 0, position, imgWidth, imgHeight); 72 | heightLeft -= pageHeight; 73 | } 74 | 75 | progress({percent: (key + 1) / fileLength * 100, currentFile: fileName}); 76 | } catch(e) { 77 | console.log(e); 78 | } 79 | if (key + 1 < fileLength) { 80 | pdf.addPage(); 81 | } 82 | } 83 | pdf.save(pdfName); 84 | }; 85 | } 86 | 87 | const _unsafeWindow = typeof unsafeWindow === 'undefined' ? window : unsafeWindow; 88 | let disabled = !!GM_getValue("pvcep_pdf_disabled"), registerId; 89 | function registerMenuCommand() { 90 | if (disabled) { 91 | _unsafeWindow.pvcepimg2pdf = null; 92 | } else _unsafeWindow.pvcepimg2pdf = img2pdf; 93 | registerId = GM_registerMenuCommand(disabled ? "❌ Disabled" : "✅ Enabled", () => { 94 | GM_unregisterMenuCommand(registerId); 95 | disabled = !disabled; 96 | GM_setValue("pvcep_pdf_disabled", disabled); 97 | registerMenuCommand(); 98 | }); 99 | } 100 | registerMenuCommand(); 101 | })(); -------------------------------------------------------------------------------- /Switch Traditional Chinese and Simplified Chinese/lib/stcasc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Chinese character type enumeration 3 | */ 4 | export declare const ChineseType: { 5 | /** Simplified Chinese */ 6 | readonly SIMPLIFIED: 0; 7 | /** Traditional Chinese */ 8 | readonly TRADITIONAL: 1; 9 | /** Unknown type */ 10 | readonly UNKNOWN: 2; 11 | }; 12 | 13 | /** 14 | * Output format enumeration 15 | */ 16 | export declare const OutputFormat: { 17 | /** Normal output - only the converted result */ 18 | readonly NORMAL: 0; 19 | /** Bracket format - outputs「Simplified(Traditional)」or「Traditional(Simplified)」*/ 20 | readonly BRACKET: 1; 21 | /** Ruby annotation format - outputs SimplifiedTraditional */ 22 | readonly RUBY: 2; 23 | }; 24 | 25 | /** 26 | * Conversion options 27 | */ 28 | export interface ConversionOptions { 29 | /** 30 | * Output format 31 | * @default OutputFormat.NORMAL 32 | */ 33 | format?: 0 | 1 | 2; 34 | } 35 | 36 | /** 37 | * Tree node for combination dictionary 38 | */ 39 | interface CombTreeNode { 40 | end?: string; 41 | [key: string]: CombTreeNode | string | undefined; 42 | } 43 | 44 | /** 45 | * Cache object for storing conversion dictionaries 46 | */ 47 | export interface ConversionCache { 48 | sc2tcCombTree?: Record; 49 | tc2scCombTree?: Record; 50 | stDict?: Record; 51 | tsDict?: Record; 52 | } 53 | 54 | /** 55 | * Custom dictionary mapping 56 | * Key: source text (simplified or traditional) 57 | * Value: target text (can be string or array of strings for multiple mappings) 58 | */ 59 | export type CustomDictionary = Record; 60 | 61 | /** 62 | * Result object returned by stcasc function 63 | */ 64 | export interface StcascConverter { 65 | /** 66 | * Convert traditional Chinese to simplified Chinese 67 | * @param text - String to convert 68 | * @param options - Conversion options 69 | * @returns Converted simplified Chinese string 70 | */ 71 | simplized(text: string, options?: ConversionOptions): string; 72 | 73 | /** 74 | * Convert traditional Chinese to simplified Chinese (array version) 75 | * @param data - Array to convert (converts all strings in the array) 76 | * @param options - Conversion options 77 | * @returns Array with converted strings 78 | */ 79 | simplized(data: T, options?: ConversionOptions): T; 80 | 81 | /** 82 | * Convert traditional Chinese to simplified Chinese (object version) 83 | * @param data - Object to convert (converts all string property values) 84 | * @param options - Conversion options 85 | * @returns Object with converted string values 86 | */ 87 | simplized>(data: T, options?: ConversionOptions): T; 88 | 89 | /** 90 | * Convert simplified Chinese to traditional Chinese 91 | * @param text - String to convert 92 | * @param options - Conversion options 93 | * @returns Converted traditional Chinese string 94 | */ 95 | traditionalized(text: string, options?: ConversionOptions): string; 96 | 97 | /** 98 | * Convert simplified Chinese to traditional Chinese (array version) 99 | * @param data - Array to convert (converts all strings in the array) 100 | * @param options - Conversion options 101 | * @returns Array with converted strings 102 | */ 103 | traditionalized(data: T, options?: ConversionOptions): T; 104 | 105 | /** 106 | * Convert simplified Chinese to traditional Chinese (object version) 107 | * @param data - Object to convert (converts all string property values) 108 | * @param options - Conversion options 109 | * @returns Object with converted string values 110 | */ 111 | traditionalized>(data: T, options?: ConversionOptions): T; 112 | 113 | /** 114 | * Detect Chinese text type 115 | * @param text - Text to detect 116 | * @returns ChineseType value (0=SIMPLIFIED, 1=TRADITIONAL, 2=UNKNOWN) 117 | */ 118 | detect(text: string): 0 | 1 | 2; 119 | 120 | /** 121 | * Cached conversion dictionaries 122 | */ 123 | cache: ConversionCache; 124 | } 125 | 126 | /** 127 | * Initialize Chinese converter with optional cache and custom dictionary 128 | * 129 | * @param cache - Optional cache object to reuse conversion dictionaries 130 | * @param custom - Optional custom dictionary for special term conversions 131 | * @param disableTerms - If true, disables built-in term conversions 132 | * @returns Converter object with conversion methods 133 | * 134 | * @example 135 | * ```typescript 136 | * import stcasc from 'switch-chinese'; 137 | * 138 | * const converter = stcasc(); 139 | * const traditional = converter.traditionalized('简体中文'); 140 | * const simplified = converter.simplized('繁體中文'); 141 | * const type = converter.detect('繁體中文'); 142 | * ``` 143 | * 144 | * @example 145 | * ```typescript 146 | * // With custom dictionary 147 | * const converter = stcasc({}, { 148 | * '自定义词': '自訂詞', 149 | * '程序': ['程式', '程序'] 150 | * }); 151 | * ``` 152 | * 153 | * @example 154 | * ```typescript 155 | * // With output format 156 | * const converter = stcasc(); 157 | * const result = converter.traditionalized('简体', { format: 1 }); 158 | * // Output: 簡體(简体) 159 | * ``` 160 | */ 161 | declare function stcasc( 162 | cache?: ConversionCache, 163 | custom?: CustomDictionary, 164 | disableTerms?: boolean 165 | ): StcascConverter; 166 | 167 | export default stcasc; 168 | -------------------------------------------------------------------------------- /Kill TieBa AD/Kill TieBa AD.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Kill TieBa AD 3 | // @name:zh-CN 贴吧广告清理 4 | // @name:zh-TW 貼吧廣告去除 5 | // @namespace hoothin 6 | // @version 1.3.2 7 | // @description Just Kill TieBa AD 8 | // @description:zh-CN 清理百度贴吧(tieba.baidu.com)内的列表伪装,帖内伪装,触点广告,页首广告,推荐应用等各类广告 9 | // @description:zh-TW 去除百度貼吧(tieba.baidu.com)内的列表偽裝,帖內偽裝,觸點廣告,頁首廣告,推薦應用等各類廣告 10 | // @author hoothin 11 | // @include http*://tieba.baidu.com/* 12 | // @exclude http*://tieba.baidu.com/ 13 | // @exclude http*://tieba.baidu.com/index.html 14 | // @grant none 15 | // @run-at document-body 16 | // @supportURL http://www.hoothin.com 17 | // @license MIT License 18 | // @compatible chrome 19 | // @compatible firefox 20 | // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=rixixi@sina.com&item_name=Greasy+Fork+donation 21 | // @contributionAmount 1 22 | // ==/UserScript== 23 | 24 | (function() { 25 | 'use strict'; 26 | var observer, option; 27 | var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 28 | var tcss = ".j_encourage_entry,#video_frs_head,#encourage_entry,.tpoint-skin,#pb_adbanner,.iframe_wrapper,div.tpoint-skin,.j_click_stats,#thread_list>li:not(.j_thread_list):not(.thread_top_list_folder),#j_p_postlist>.clearfix:not([data-field*=post_id]){display:none !important;}"; 29 | var snod = document.createElement('style'); 30 | snod.innerHTML = tcss; 31 | document.getElementsByTagName("head")[0].appendChild(snod); 32 | var content = document.querySelector("#content"); 33 | if(content){ 34 | delAD("#thread_list","LI"); 35 | observer = new MutationObserver(function(records){ 36 | delAD("#thread_list","LI"); 37 | }); 38 | option = { 39 | 'childList': true, 40 | 'subtree': true 41 | }; 42 | observer.observe(content, option); 43 | }else{ 44 | content=document.querySelector(".l_container"); 45 | if(content){ 46 | delAD("#j_p_postlist","DIV"); 47 | observer = new MutationObserver(function(records){ 48 | delAD("#j_p_postlist","DIV"); 49 | }); 50 | option = { 51 | 'childList': true, 52 | 'subtree': true 53 | }; 54 | observer.observe(content, option); 55 | }else{ 56 | content=document.querySelector(".post_list"); 57 | if(content){ 58 | delAD(".threads_list","LI"); 59 | observer = new MutationObserver(function(records){ 60 | delAD(".threads_list","LI"); 61 | }); 62 | option = { 63 | 'childList': true, 64 | 'subtree': true 65 | }; 66 | observer.observe(content, option); 67 | } 68 | } 69 | } 70 | 71 | function delAD(a,b){ 72 | var threadList = document.querySelector(a+">"+a),i; 73 | if(!threadList) threadList = document.querySelector(a); 74 | if(!threadList) return; 75 | var delList = []; 76 | for(i=0;i 35 | 36 | 37 | Our Love Story 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
    46 |
    47 |
    48 | 49 |
    50 |
    51 | ${valentinName}, I have fallen in love with you for 52 |
    53 |
    54 |
    55 | Love u forever and ever.
    56 |
    - ${myName}
    57 |
    58 |
    59 |
    60 |
    61 |
    62 | 85 | 86 | `; 87 | GM_openInTab('data:text/html;charset=utf-8,' + encodeURIComponent(html),false); 88 | }else{ 89 | var listWrapper=document.querySelector(".s-news-list-wrapper"); 90 | if(listWrapper){ 91 | var valentineItem=document.createElement("div"); 92 | valentineItem.className="s-news-special s-news-item s-news-special-item-tpl-2 s-opacity-blank8"; 93 | valentineItem.innerHTML=` `; 94 | listWrapper.insertBefore(valentineItem,listWrapper.firstChild); 95 | } 96 | } 97 | })(); -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | rixixi@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /Invite Code Tool/Invite Code Tool.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 注册邀请码抢码工具 3 | // @name:en Tool for register with invite code 4 | // @name:zh-TW 注冊邀請碼搶碼工具 5 | // @namespace hoothin 6 | // @version 0.6 7 | // @description 自动遍历论坛注册邀请码得出正确结果 8 | // @description:en Just a tool for register with invite code 9 | // @description:zh-TW 自動遍歷論壇注冊邀請碼得出正確結果 10 | // @author hoothin 11 | // @include * 12 | // @exclude http*://*.baidu.* 13 | // @exclude http*://*.bing.* 14 | // @exclude http*://*.google.* 15 | // @grant GM_registerMenuCommand 16 | // @grant GM_setValue 17 | // @grant GM_getValue 18 | // @grant GM_deleteValue 19 | // @grant unsafeWindow 20 | // @license MIT License 21 | // @compatible chrome 22 | // @compatible firefox 23 | // ==/UserScript== 24 | 25 | (function() { 26 | 'use strict'; 27 | var is1024=document.title.indexOf('\u8349\u69b4') != -1; 28 | var firefox=navigator.userAgent.toLowerCase().indexOf('firefox')!=-1; 29 | var invitecode=document.querySelector((is1024?"#invcode":"#invitecode")), 30 | chkInvitecode=document.querySelector((is1024?"#check_info_invcode":"#chk_invitecode")), 31 | codeChar=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],checkFun,checkinvite,preTxt="",codeArr; 32 | String.prototype.pmatch = function(reg){ 33 | if(!(reg instanceof RegExp))return 0; 34 | var a=[]; 35 | if(!reg.global){ 36 | a = this.match(reg); 37 | return a? [a.slice(1,a.length)] : 0; 38 | } 39 | var b=reg.exec(this); 40 | while(b){ 41 | b.shift(); 42 | a.push(b[0]); 43 | b=reg.exec(this); 44 | } 45 | return a.length>0?a:0; 46 | }; 47 | function checkCode(){ 48 | if(checkFun)clearInterval(checkFun); 49 | var checkNext=function(){ 50 | if(codeArr.length===0){ 51 | clearInterval(checkFun); 52 | if(checkinvite)clearInterval(checkinvite); 53 | alert("没有找到正确的邀请码!"); 54 | return; 55 | } 56 | invitecode.value=codeArr.shift(); 57 | if(is1024){ 58 | unsafeWindow.invcodecheck(); 59 | }else{ 60 | unsafeWindow.checkinvite(); 61 | } 62 | }; 63 | var checkBtn=invitecode.parentNode.querySelector(".btn"); 64 | checkFun = setInterval(function() { 65 | if(preTxt!=chkInvitecode.innerHTML){ 66 | preTxt=chkInvitecode.innerHTML; 67 | if(chkInvitecode.innerHTML){ 68 | if(is1024){ 69 | if(chkInvitecode.innerHTML.indexOf("green")!=-1){ 70 | if(checkinvite)clearInterval(checkinvite); 71 | clearInterval(checkFun); 72 | alert("已匹配到正确的邀请码!"); 73 | }else if(chkInvitecode.innerHTML.indexOf("red")!=-1){ 74 | if(checkinvite)clearInterval(checkinvite); 75 | checkinvite=setInterval(function() {checkBtn.click();},2000); 76 | checkNext(); 77 | } 78 | }else{ 79 | if(chkInvitecode.innerHTML.indexOf("邀请码错误")==-1){ 80 | clearInterval(checkFun); 81 | alert("已匹配到正确的邀请码!"); 82 | }else{ 83 | checkNext(); 84 | } 85 | } 86 | } 87 | } 88 | },100); 89 | checkNext(); 90 | } 91 | function geneCodeArr(){ 92 | var tempCode=[]; 93 | codeArr.forEach(function(item){ 94 | if(item.indexOf("*")!=-1){ 95 | for(var char of codeChar){ 96 | var tempItem=item.replace(/\*/,char); 97 | if(tempCode.toString().indexOf(tempItem)==-1){ 98 | tempCode.push(tempItem); 99 | } 100 | } 101 | }else if(tempCode.toString().indexOf(item)==-1){ 102 | tempCode.push(item); 103 | } 104 | }); 105 | codeArr=[]; 106 | while(tempCode.length>0){ 107 | var random=Math.floor(Math.random()*tempCode.length); 108 | var curCode=tempCode[random]; 109 | codeArr.push(curCode); 110 | tempCode.splice(random,1); 111 | } 112 | } 113 | if(invitecode){ 114 | var copiedCode=GM_getValue("copiedCode"); 115 | if(copiedCode){ 116 | GM_deleteValue("copiedCode"); 117 | codeArr=copiedCode; 118 | checkCode(); 119 | } 120 | GM_registerMenuCommand("开始筛选邀请码", function(){ 121 | var codeStr=prompt("输入邀请码:",""); 122 | if(!codeStr)return; 123 | codeArr=codeStr.pmatch((is1024?/\b([0-9a-z\*]{16})\b/gi:/(?:^|c=|[^=\.\/])\b([0-9a-z]{6})(?:\s|$)/gi)); 124 | if(codeArr===0)return; 125 | geneCodeArr(); 126 | checkCode(); 127 | }); 128 | }else{ 129 | if(is1024){ 130 | codeArr=(firefox?document.body.textContent:document.body.innerText).pmatch(/(?:^|[::\s])\b([0-9a-z\*]{16})\b/gi); 131 | if(codeArr!==0){ 132 | if(window.confirm("检测到邀请码,是否立即前往注册?")){ 133 | geneCodeArr(); 134 | GM_setValue("copiedCode",codeArr); 135 | location.href="/register.php"; 136 | } 137 | } 138 | } 139 | } 140 | })(); -------------------------------------------------------------------------------- /MoreSteamRatings/MoreSteamRatings.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name MoreSteamRatings 3 | // @name:zh-CN Steam游戏评分集 4 | // @name:zh-TW Steam遊戲評分集 5 | // @namespace hoothin 6 | // @version 0.2.2 7 | // @description Show more game ratings on steam store 8 | // @description:zh-CN 在Steam游戏详情页显示更多网站评分 9 | // @description:zh-TW 在Steam遊戲詳情頁顯示更多網站評分 10 | // @author hoothin 11 | // @include http*://store.steampowered.com/app/* 12 | // @grant GM_xmlhttpRequest 13 | // @connect www.metacritic.com 14 | // @connect www.gamerankings.com 15 | // @connect www.gamespot.com 16 | // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=rixixi@sina.com&item_name=Greasy+Fork+donation 17 | // @contributionAmount 1 18 | // ==/UserScript== 19 | 20 | var appName=document.querySelector("div.apphub_AppName"); 21 | if(!appName)return; 22 | var gameName=getRightName(appName.innerHTML); 23 | var userReviews=document.querySelector("div.user_reviews"); 24 | var metascore=document.querySelector("div.responsive_apppage_reviewblock"); 25 | //getMcScore(); 26 | getGsScore(); 27 | getGrScore(); 28 | 29 | function getRightName(s){ 30 | return s.replace(/:\s|:|\s/g,"-").toLowerCase(); 31 | } 32 | 33 | function getMcScore(){ 34 | getResult("http://www.metacritic.com/game/pc/"+gameName, function(d){ 35 | let score=d.querySelector("span[itemprop=ratingValue]"); 36 | if(score){ 37 | let title=document.createElement("div"); 38 | title.onclick=function(){window.open("http://www.metacritic.com/game/pc/"+gameName);}; 39 | title.style.cssText="color:#8f98a0;cursor: pointer;"; 40 | title.innerHTML="
    Metacritic:
    "; 41 | userReviews.parentNode.insertBefore(title,userReviews.nextSibling); 42 | let scoreSpan=document.createElement("span"); 43 | scoreSpan.style.cssText="color:#A34C25;font-size:14px"; 44 | scoreSpan.innerHTML=score.innerHTML; 45 | title.appendChild(scoreSpan); 46 | } 47 | }); 48 | } 49 | 50 | function getGsScore(){ 51 | getResult("http://www.gamespot.com/"+gameName, function(d){ 52 | let score=d.querySelector("span[itemprop=ratingValue]"); 53 | if(score){ 54 | /*let title=document.createElement("div"); 55 | title.onclick=function(){window.open("http://www.gamespot.com/"+gameName);}; 56 | title.style.cssText="color:#8f98a0;cursor: pointer;"; 57 | title.innerHTML="
    Gamespot:
    "; 58 | userReviews.parentNode.insertBefore(title,userReviews.nextSibling); 59 | let scoreSpan=document.createElement("span"); 60 | scoreSpan.style.cssText="color:#A34C25;font-size:14px"; 61 | scoreSpan.innerHTML=score.innerHTML; 62 | title.appendChild(scoreSpan);*/ 63 | 64 | let gameScore=metascore.cloneNode(true); 65 | var gameBack=gameScore.querySelector("#game_area_metascore"); 66 | gameBack.style.backgroundImage="url(http://static1.gamespot.com/bundles/gamespotsite/images/logo-flat-midsize.png)"; 67 | gameBack.style.backgroundSize="141px"; 68 | gameBack.style.backgroundPosition="0 -10px"; 69 | let scoreValue=gameBack.querySelectorAll("span"); 70 | scoreValue[0].innerHTML=score.innerHTML; 71 | scoreValue[2].innerHTML="10"; 72 | let scoreLink=gameScore.querySelector("#game_area_metalink>a"); 73 | scoreLink.href="http://www.gamespot.com/"+gameName; 74 | scoreLink.innerHTML="Read Gamespot Reviews"; 75 | metascore.parentNode.appendChild(gameScore); 76 | } 77 | }); 78 | } 79 | 80 | function getGrScore(){ 81 | getResult("http://www.gamerankings.com/browse.html?search="+encodeURI(appName.innerHTML)+"&site=pc&numrev=3", function(d){ 82 | let score=d.querySelector(".pod>.body>table>tbody>tr"); 83 | if(score){ 84 | let link="http://www.gamerankings.com"+score.querySelector("td>a").getAttribute("href"); 85 | /*let title=document.createElement("div"); 86 | title.onclick=function(){window.open(link);}; 87 | title.style.cssText="color:#8f98a0;cursor: pointer;"; 88 | title.innerHTML="
    Gamerankings:
    "; 89 | userReviews.parentNode.insertBefore(title,userReviews.nextSibling); 90 | let scoreSpan=document.createElement("span"); 91 | scoreSpan.style.cssText="color:#A34C25;font-size:14px"; 92 | scoreSpan.innerHTML=score.querySelector("td>span").innerHTML; 93 | title.appendChild(scoreSpan);*/ 94 | 95 | let gameScore=metascore.cloneNode(true); 96 | var gameBack=gameScore.querySelector("#game_area_metascore"); 97 | gameBack.style.backgroundImage="url(http://img.gamefaqs.net/images/default/gr_logo.gif)"; 98 | gameBack.style.backgroundSize="160px"; 99 | let scoreValue=gameBack.querySelectorAll("span"); 100 | scoreValue[0].innerHTML=score.querySelector("td>span").innerText; 101 | scoreValue[1].innerHTML=scoreValue[2].innerHTML=""; 102 | let scoreLink=gameScore.querySelector("#game_area_metalink>a"); 103 | scoreLink.href=link; 104 | scoreLink.innerHTML="Read Gamerankings Reviews"; 105 | metascore.parentNode.appendChild(gameScore); 106 | } 107 | }); 108 | } 109 | 110 | function getResult(url,callBack){ 111 | GM_xmlhttpRequest({ 112 | method: 'GET', 113 | url: url, 114 | onload: function (d) { 115 | let doc = document.implementation.createHTMLDocument(''); 116 | doc.documentElement.innerHTML = d.responseText; 117 | callBack(doc); 118 | } 119 | }); 120 | } -------------------------------------------------------------------------------- /Pagetual/README.md: -------------------------------------------------------------------------------- 1 | [☯️](https://greasyfork.org/scripts/438684 "Install from greasyfork")東方永頁機 [v.1.9.37.125](https://hoothin.github.io/UserScripts/Pagetual/pagetual.user.js "Latest version") 2 | == 3 | *Pagetual - Perpetual pages. Auto loading paginated web pages for 90% of all web sites !* 4 | 5 | 🔧CONFIGURATION PAGE 6 | 7 |

    8 |
      9 | https://raw.githubusercontent.com/hoothin/UserScripts/master/Pagetual/pagetualRules.json
     10 | 
    11 | 12 | --- 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
    Buy me a coffee if you get help💞

    PayPal

    Ko-fi

    愛發電
    Join 💬Discord
    Follow 🕊️twitter
    Send 📧email
    Made with ❤️ by Hoothin
    39 | 40 |
    41 |

    Pagetual User-defined rules cases

    42 | 43 | + [TerenceCK pagetualRules](https://github.com/TerenceCK/pagetualRules/blob/main/happymh.json) 44 | + [Liu's-Pagetual-Rule](https://github.com/JPLiu/TestFiles/blob/main/UserScripts/Pagetual/Liu's-Pagetual-Rule.json) 45 | + [skofkyo pagetualRules_EX](https://github.com/skofkyo/AutoPager/blob/main/pagetualRules_EX.json) 46 | + [MovByte eToolsPagetual](https://gist.github.com/MovByte/a585456490d2e1c8ca815871db0887f7) 47 |
    48 | 49 |
    50 | 51 |

    Call functionality from other extensions

    52 |
    53 | 54 | 1. **Immediately load next page** 55 | 56 | > Please send the following message body: 57 | ``` 58 | command: "pagetual" 59 | action: "nextPage" 60 | detail: The number of pages to turn, 0 for unlimited, -1 to stop 61 | ``` 62 | 63 | > For example: 64 | ``` 65 | window.postMessage({ action: 'nextPage', command: 'patetual', detail: 5 }, '*'); 66 | ``` 67 | 68 | 2. **Set configuration** 69 | 70 | > Please send the following message body: 71 | ``` 72 | command: "pagetual" 73 | action: "config" 74 | detail: The configuration item to be changed 75 | ``` 76 | 77 | > For example: 78 | ``` 79 | window.postMessage({ action: 'config', command: 'patetual', detail: {enableWhiteList: true} }, '*'); 80 | ``` 81 | 82 | 3. **Click load more button** 83 | 84 | > Please send the following message body: 85 | ``` 86 | command: "pagetual" 87 | action: "loadMore" 88 | detail: null by default, 0 for unlimited checking load more button, -1 to stop 89 | ``` 90 | 91 | > For example: 92 | ``` 93 | window.postMessage({ action: 'loadMore', command: 'patetual', detail: 0 }, '*'); 94 | ``` 95 | + **Receive messages** 96 | 97 | > When the next page is inserted, the following message body will be sent: 98 | ``` 99 | { 100 | action: 'insert', 101 | command: 'patetual' 102 | } 103 | ``` 104 | 105 | > When the last page has been reached, the following message body will be sent: 106 | ``` 107 | { 108 | action: 'lastPage', 109 | command: 'patetual' 110 | } 111 | ``` 112 | 113 |
    114 | 115 | [Rules example](https://pagetual.hoothin.com/en/rule.html) 116 | == 117 | ``` json 118 | [ 119 | { 120 | "name":"beauty", 121 | "url":"^https://www\\.jpmn-demo\\.com/", 122 | "pageElement":"p>img" 123 | }, 124 | { 125 | "name":"Expreview", 126 | "url":"^https://www\\.expreview-demo\\.com/", 127 | "loadMore":"span.load" 128 | } 129 | ] 130 | ``` 131 | 132 | name 133 | -- 134 | Name of the target site 135 | ```JSON 136 | "name": "Site name" 137 | ``` 138 | 139 | author 140 | -- 141 | Author of this rule 142 | ```JSON 143 | "author": "Hoothin" 144 | ``` 145 | 146 | example 147 | -- 148 | Example url of this rule 149 | ```JSON 150 | "example": "https://abc.com" 151 | ``` 152 | 153 | [url](https://pagetual.hoothin.com/rules/url.html) 154 | -- 155 | RegExp for the url of target site 156 | 157 | [nextLink](https://pagetual.hoothin.com/rules/nextLink.html) 158 | -- 159 | Selector or xpath of next page link, disable when set to 0, you can let it to be a array to contains multiple next links. You may leave it empty because it will be generated automatically. 160 | 161 | [pageElement](https://pagetual.hoothin.com/rules/pageElement.html) 162 | -- 163 | Selector or xpath of main content which need to insert, you can let it to be a array to contains multiple page elements. You may leave it empty because it will be generated automatically. 164 | 165 | [enable](https://pagetual.hoothin.com/rules/enable.html) 166 | -- 167 | 0 means stop action when all matched 168 | 169 | [include](https://pagetual.hoothin.com/rules/include.html) 170 | -- 171 | Selector or xpath of the element which must include 172 | 173 | [exclude](https://pagetual.hoothin.com/rules/exclude.html) 174 | -- 175 | Selector or xpath of the element which must not include 176 | 177 | [action](https://pagetual.hoothin.com/rules/action.html) 178 | -- 179 | 0 means load url and insert with static html, 1 means load by iframe so that dynamic javaScript code on page may effect, 2 means force insert iframe to bottom 180 | 181 | [loadMore](https://pagetual.hoothin.com/rules/loadMore.html) 182 | -- 183 | Selector of "load more" button you want to auto click 184 | -------------------------------------------------------------------------------- /Switch Traditional Chinese and Simplified Chinese/lib/test.js: -------------------------------------------------------------------------------- 1 | import stcasc, { ChineseType, OutputFormat } from './stcasc.lib.js'; 2 | 3 | console.log('========== 简繁转换库测试 ==========\n'); 4 | 5 | // 初始化 6 | const { traditionalized, simplized, detect } = stcasc(); 7 | 8 | // 测试 1: 基础简体转繁体 9 | console.log('测试 1: 基础简体转繁体'); 10 | const sc1 = '简繁转换 繁简切换 香烟 香烟袅袅 烟雾里 里长面子'; 11 | const tc1 = traditionalized(sc1); 12 | console.log('输入:', sc1); 13 | console.log('输出:', tc1); 14 | console.log(''); 15 | 16 | // 测试 2: 基础繁体转简体 17 | console.log('测试 2: 基础繁体转简体'); 18 | const tc2 = '繁體中文 簡體中文'; 19 | const sc2 = simplized(tc2); 20 | console.log('输入:', tc2); 21 | console.log('输出:', sc2); 22 | console.log(''); 23 | 24 | // 测试 3: 检测简体中文 25 | console.log('测试 3: 检测简体中文'); 26 | const text1 = '这是简体中文'; 27 | const type1 = detect(text1); 28 | console.log('文本:', text1); 29 | console.log('类型:', type1 === ChineseType.SIMPLIFIED ? '简体中文' : '未知'); 30 | console.log('枚举值:', type1); 31 | console.log(''); 32 | 33 | // 测试 4: 检测繁体中文 34 | console.log('测试 4: 检测繁体中文'); 35 | const text2 = '這是繁體中文'; 36 | const type2 = detect(text2); 37 | console.log('文本:', text2); 38 | console.log('类型:', type2 === ChineseType.TRADITIONAL ? '繁体中文' : '未知'); 39 | console.log('枚举值:', type2); 40 | console.log(''); 41 | 42 | // 测试 5: 检测非中文 43 | console.log('测试 5: 检测非中文'); 44 | const text3 = 'English Text'; 45 | const type3 = detect(text3); 46 | console.log('文本:', text3); 47 | console.log('类型:', type3 === ChineseType.UNKNOWN ? '未知' : '中文'); 48 | console.log('枚举值:', type3); 49 | console.log(''); 50 | 51 | // 测试 6: 输出格式 - BRACKET(括号格式) 52 | console.log('测试 6: 输出格式 - BRACKET(括号格式)'); 53 | const sc3 = '简体中文转换'; 54 | const tc3 = traditionalized(sc3, { format: OutputFormat.BRACKET }); 55 | console.log('输入:', sc3); 56 | console.log('输出:', tc3); 57 | console.log(''); 58 | 59 | // 测试 7: 输出格式 - RUBY(HTML ruby标签格式) 60 | console.log('测试 7: 输出格式 - RUBY(HTML ruby标签格式)'); 61 | const sc4 = '简体中文'; 62 | const tc4 = traditionalized(sc4, { format: OutputFormat.RUBY }); 63 | console.log('输入:', sc4); 64 | console.log('输出:', tc4); 65 | console.log(''); 66 | 67 | // 测试 8: 繁体转简体 - BRACKET格式 68 | console.log('测试 8: 繁体转简体 - BRACKET格式'); 69 | const tc5 = '繁體中文'; 70 | const sc5 = simplized(tc5, { format: OutputFormat.BRACKET }); 71 | console.log('输入:', tc5); 72 | console.log('输出:', sc5); 73 | console.log(''); 74 | 75 | // 测试 9: 繁体转简体 - RUBY格式 76 | console.log('测试 9: 繁体转简体 - RUBY格式'); 77 | const tc6 = '繁體中文'; 78 | const sc6 = simplized(tc6, { format: OutputFormat.RUBY }); 79 | console.log('输入:', tc6); 80 | console.log('输出:', sc6); 81 | console.log(''); 82 | 83 | // 测试 10: 复杂文本转换 - 正常格式 84 | console.log('测试 10: 复杂文本转换 - 正常格式'); 85 | const complex = '吃干面 把考卷发回来 卷发 知识产权'; 86 | const complexTc = traditionalized(complex); 87 | console.log('输入:', complex); 88 | console.log('输出:', complexTc); 89 | console.log(''); 90 | 91 | // 测试 11: 复杂文本转换 - BRACKET格式 92 | console.log('测试 11: 复杂文本转换 - BRACKET格式'); 93 | const complexBracket = traditionalized(complex, { format: OutputFormat.BRACKET }); 94 | console.log('输入:', complex); 95 | console.log('输出:', complexBracket); 96 | console.log(''); 97 | 98 | // 测试 12: 术语转换 99 | console.log('测试 12: 术语转换'); 100 | const terms = '软件 硬盘 网络 服务器 鼠标'; 101 | const termsTc = traditionalized(terms); 102 | console.log('输入:', terms); 103 | console.log('输出:', termsTc); 104 | console.log(''); 105 | 106 | // 测试 13: 混合文本 107 | console.log('测试 13: 混合文本'); 108 | const mixed = 'This is 简体中文 and English'; 109 | const mixedTc = traditionalized(mixed); 110 | console.log('输入:', mixed); 111 | console.log('输出:', mixedTc); 112 | console.log(''); 113 | 114 | // ========== 新增测试:Array/Object 支持 ========== 115 | console.log('========== Array/Object 测试 ==========\n'); 116 | 117 | // 测试 14: 转换数组(简体->繁体) 118 | console.log('测试 14: 转换数组(简体->繁体)'); 119 | const arr1 = ['简体中文', '软件', '硬盘', 123, true, null]; 120 | const arr1Tc = traditionalized(arr1); 121 | console.log('输入:', arr1); 122 | console.log('输出:', arr1Tc); 123 | console.log(''); 124 | 125 | // 测试 15: 转换数组(繁体->简体) 126 | console.log('测试 15: 转换数组(繁体->简体)'); 127 | const arr2 = ['繁體中文', '軟體', '硬碟', 456, false]; 128 | const arr2Sc = simplized(arr2); 129 | console.log('输入:', arr2); 130 | console.log('输出:', arr2Sc); 131 | console.log(''); 132 | 133 | // 测试 16: 转换对象(简体->繁体) 134 | console.log('测试 16: 转换对象(简体->繁体)'); 135 | const obj1 = { 136 | title: '简体中文标题', 137 | description: '这是一个简体中文描述', 138 | count: 100, 139 | active: true, 140 | tags: ['软件', '网络', '服务器'] 141 | }; 142 | const obj1Tc = traditionalized(obj1); 143 | console.log('输入:', JSON.stringify(obj1, null, 2)); 144 | console.log('输出:', JSON.stringify(obj1Tc, null, 2)); 145 | console.log(''); 146 | 147 | // 测试 17: 转换对象(繁体->简体) 148 | console.log('测试 17: 转换对象(繁体->简体)'); 149 | const obj2 = { 150 | title: '繁體中文標題', 151 | description: '這是一個繁體中文描述', 152 | price: 99.99, 153 | items: ['軟體', '硬碟'] 154 | }; 155 | const obj2Sc = simplized(obj2); 156 | console.log('输入:', JSON.stringify(obj2, null, 2)); 157 | console.log('输出:', JSON.stringify(obj2Sc, null, 2)); 158 | console.log(''); 159 | 160 | // 测试 18: 转换嵌套数组 161 | console.log('测试 18: 转换嵌套数组'); 162 | const nestedArr = [ 163 | '简体中文', 164 | ['软件', '硬盘'], 165 | [['网络', '服务器']] 166 | ]; 167 | const nestedArrTc = traditionalized(nestedArr); 168 | console.log('输入:', JSON.stringify(nestedArr)); 169 | console.log('输出:', JSON.stringify(nestedArrTc)); 170 | console.log(''); 171 | 172 | // 测试 19: 转换嵌套对象 173 | console.log('测试 19: 转换嵌套对象'); 174 | const nestedObj = { 175 | user: { 176 | name: '简体名称', 177 | profile: { 178 | bio: '这是简体中文简介', 179 | skills: ['软件开发', '网络管理'] 180 | } 181 | }, 182 | count: 42 183 | }; 184 | const nestedObjTc = traditionalized(nestedObj); 185 | console.log('输入:', JSON.stringify(nestedObj, null, 2)); 186 | console.log('输出:', JSON.stringify(nestedObjTc, null, 2)); 187 | console.log(''); 188 | 189 | // 测试 20: 数组转换 - BRACKET 格式 190 | console.log('测试 20: 数组转换 - BRACKET 格式'); 191 | const arr3 = ['简体', '中文']; 192 | const arr3Bracket = traditionalized(arr3, { format: OutputFormat.BRACKET }); 193 | console.log('输入:', arr3); 194 | console.log('输出:', arr3Bracket); 195 | console.log(''); 196 | 197 | // 测试 21: 对象转换 - RUBY 格式 198 | console.log('测试 21: 对象转换 - RUBY 格式'); 199 | const obj3 = { 200 | text1: '简体', 201 | text2: '中文' 202 | }; 203 | const obj3Ruby = traditionalized(obj3, { format: OutputFormat.RUBY }); 204 | console.log('输入:', JSON.stringify(obj3, null, 2)); 205 | console.log('输出:', JSON.stringify(obj3Ruby, null, 2)); 206 | console.log(''); 207 | 208 | // 测试 22: 处理 null 和 undefined 209 | console.log('测试 22: 处理 null 和 undefined'); 210 | console.log('null 输入:', traditionalized(null)); 211 | console.log('undefined 输入:', traditionalized(undefined)); 212 | console.log('包含 null 的数组:', traditionalized(['简体', null, '中文'])); 213 | console.log(''); 214 | 215 | console.log('========== 测试完成 =========='); 216 | -------------------------------------------------------------------------------- /Easy offline/README.MD: -------------------------------------------------------------------------------- 1 | 一鍵離線下載 2 | = 3 | 在磁力鏈接(magnet)\種子(torrent)\電驢(ed2k)\視頻\壓縮包或其他下載鏈接旁添加按鈕,點擊自動離線下載至網盤 4 | 5 | ### 默認支持鏈接 6 | * 磁力鏈接 7 | * 電驢鏈接 8 | * 種子文件 9 | * 壓縮包 `rar 7z zip` 10 | * 鏡像文件 `iso` 11 | * 視頻文件 `mp4 rmvb mkv avi` 12 | 13 | ### 用法 14 | - 按下 **`F9`** 快速在當前網站禁用或啓用並記錄選擇 15 | - **`Alt + F9`** 自定義下載,選中文本則下載文字對應的鏈接,鼠標指向鏈接則下載該鏈接,沒有選中則彈框粘貼鏈接下載 16 | - 按住 **`Ctrl + Shift`** 點擊批量離線當前頁面中所有資源(如果我給該網盤寫了批量離線功能的話),實際也沒鳥用,度盤批量離線時動不動就網絡繁忙了 17 | - 網盤排序功能,設置頁面拖拽圖標即可進行排序 18 | - 網盤設置功能,點擊圖標可設置是否啓用網盤 19 | - 度盤默認下載路徑設置 20 | - 設置頁面填入正則表達式可增加支持鏈接,可設置是否僅當鼠標經過時顯示圖標 21 | - **`Alt + x`** 批量複製頁面資源 22 | 23 | ### 自定義設置示例 24 | * 安卓安裝包 `\.apk$` 25 | * 某服裝擴展 `\.Outfit\d{4}\.txx$` 26 | * 某ftp `^ftp:\/\/user:pass@127\.0\.0\.1` 27 | * 某帶參mp4視頻 `mp4\?[^\/]+$` 28 | 29 | ### 自定義例子 - Github鏡像加速下載,點擊下方導入 30 | 配置方法在設置項内,有其他規則用`
    `標簽分享到 [反饋](https://github.com/hoothin/UserScripts/issues) 亦可點擊導入。例如此處的下載圖標:[Github](https://github.com/hoothin/imgCodeCheck/releases/tag/0.1)
     31 | 
     32 | https://download.fastgit.org/${https?://[^/]+(.*)}@@Fastgit@@github\.com.*(releases\/download|archive\/refs\/)@@@@ffff9f
     33 | https://pd.zwc365.com/seturl/$url@@ZWC365@@github\.com.*(releases\/download|archive\/refs\/)@@@@0fffff
     34 | https://gh.api.99988866.xyz/$url@@99988866@@github\.com.*(releases\/download|archive\/refs\/)@@@@9fffff
     35 | https://ghproxy.com/$url@@Ghproxy@@github\.com.*(releases\/download|archive\/refs\/)@@@@ff0fff
     36 | https://github.rc1844.workers.dev${https?://[^/]+(.*)}@@RC1844@@github\.com.*(releases\/download|archive\/refs\/)@@@@ff9fff
     37 | https://ghproxy.fsou.cc/$url@@Fsou@@github\.com.*(releases\/download|archive\/refs\/)@@@@ffff0f
     38 | 
    39 | 40 | ### 自定義例子2 - Aria2 下載 41 | 同樣是點擊下方導入 42 |
     43 | http://aria.hoothin.com/#!/new/$base64@@Aria2@@@@data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABOFBMVEUAAADSVF7SVF7SVF7LVWDSVF7QVF/SVF7SVF7SVF7SVF7SVF7SVF7RVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF5ma4Di4uLSVF7v7+9DQ0NvaX1+ZniUYXGtXGppan+cYG+TYXLs7OyyW2h4tsiVlJWxs7ylpaWgoKBwaX2JZHVRVFxNT1VNTU1KSkxGRkd0uMzKysp5tceHipjDV2JYWFrr5ufa2tvT09Pjycu9v8a5u8PCwsK+vr6rrbego6+Tp62pqamZnKmloaGjj5l5fY+MfY60gozDfIa3foJkaHzTX2hYW2i6UVluSEuK2/Pd3d7X0NLExcm1tbWRlKKbm5uohJCOjo6GhoqOeInPgIh0coV8fHx7e3vRbXbObXaNY3SgX25hYmRhYWHJVmGOTFGNTFENIl9FAAAAF3RSTlMAJNEM+vr1iQjpyFfr6pybmjLusJhyIzaw7jcAAAHlSURBVDjLfZNnU+NADIbXduyQBBLq2fK6JcQmF0gvtOOOztGv90Ln//8Ddm3txkNmeD54vNI7klYrkRFaYT6f0/Vcfr6gkXGUklH13HoQ1F2vapSUZ+6JbKbsmIzvR/zrlDPZibT/lerXTc4fuDJj6r6aCjKTq5gJZwDH+FvJzcj0U8to/A+M93hYnlIwv+qh6RhijkQMNakj66PhF8BBr3cAZwEa/GxcYMbB8284CT90whOZxMnwJKUyHvurG/thpxPub3wykXKR9c8QATZtu7YT9nZqlvVVhDA0Uqji4XDVtrdeM95a1uYhGqsFMi2usGfb9uJWrcb81toeGr1pknfxf8nmLFox79Do5smkKOFNWrAkipgkevCSINBRMJ5CCmSK7ZTg47ZMMSqyHwt+fOOCbl8WObrm0OKC4R0X7A5PxTVlo87pFy5oNrngLz0XjZKtXqH/uIBSLmjRhmw1KSaP1WIuIdiltCUfiyjJc7cp/bm2vt5qd7ufbylt43OPBoayqFEUNZtRZJ42KE0GBkeuwgUr7FIAl5cArHWNdjxyWmpomd+8AXh8ALjmNcuhTY/9AODiAsCXYy9RVN/hGRLuXVafWJz06nmAeLh6z5d3AMjAKCpkHG1hTp3V9Vl1biG1/k8fR16xKi9r1wAAAABJRU5ErkJggg==@@ff2a00
     44 | 
    45 | *之所以把Aria2做成自定義是因為每個人的Aria2UI網址都不一樣,用我的伺服器管理本地的Aria2服務需要允許Chrome訪問本地資源,訪問 chrome://flags/#block-insecure-private-network-requests 並關閉即可。不想關閉的話直接打開設置把上面的網址換成自己本地的即可,例如 127.0.0.1 46 | 47 | ### 自定義例子3 - Post 請求 RPC 遠程下載 48 |
     49 | p:http://192.168.32.1:6800/jsonrpc?id=$random&jsonrpc=2.0&method=aria2.addUri&params=["token:123456",["$url"]]@@Aria2RPC@@@@@@df2a00
     50 | 
    51 | 導入后需要自行修改網址与 token 密鑰 52 | 53 | ### 自定義例子4 - 複製所有包含 “22590-easy-offline” 的連結為 markdown 格式 54 | (按住 Alt 顯示圖標,使用 ctrl + shift 複製全部) 55 |
     56 | c:[$text "$title"]($url)@@Markdown@@22590-easy-offline@@@@df2a00@@1
     57 | 
    58 | 59 | ### 自定義例子5 - 谷歌翻譯選中文本 60 | 默認是按住Alt鍵划選 61 |
     62 | https://translate.google.com/?client=gtx&dj=1&q=$text&sl=auto&tl=zh-CN&hl=zh-CN&ie=UTF-8&oe=UTF-8&source=icon&dt=t&dt=bd@@Translate@@@@data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAExklEQVRoge2Y+08UVxTH/dNmtYRHwNKHDW1tIWl/sK1QbFoSitXa9i642wWxKIK0ysOCLBSwBSWQslpboD54SGVNbAkB0cqjIIic+5jTH2b2gczM7o7DzpLsyfeHzeydmfM5994z555dEoEdrV22e5AEsNuDJIDdHiQB7PYgCRBpRJoLDtazggbzym9g+fX0je+oDQCfXGDL62iJCRlbhnhcAdLdsPzUGu+D9uVPLH4A+Q00Gp/WNnBhFRfXogLoGRUJB1DZyyUC+05GNbjvThLANEDPmChqYVuVU0UlAqnHoaiZBfVZQO5unigAtQNmckhuDU0UgJ9HxKEmFlShjjLcIBHI9EBhEytsZKWXEmYGojEuMKucSgTc3Szh9kA0dmdGVu69fk8kNMBXHSzDDVkeeLQsh193dzOJwMsVFLQnIGEARqfVSJdfDnm6sIppLpAInOrnejcmCgAiHmpiEoGXSuHvf9VJIF1MIpBSBg83T0uCAvjn5D2lIBH44BxlHPsnhIOARKCyVzf8iQWAgW+wRKDEy1KPg0TgtUq6Yli9xhWgIBLAM4q5NaEqf7cThu5rJx97AAobdVJJwGaX5APnQgBpLuif0AaQA5qal1sGeTRqHuTFFyPX3iYBGMeLwyLdHYq98iOlDB6vGFPHZq3DEeqXmAG4wF//EuErp7iVPViSm37naS4gXREmLVaTEd85Y3QWjQFgbQM7b25yfW857R0XwZQ5syiPTOsmUNNW2Gi0kGIAuOYXjsBScTiBdLEoT2GJAoCI3/v4nlIo8TL/nPWRjgeAkHFhFSnHF2lVzD/BsWl5bFqemJE3oigXzQN8rLWJKccSL3v3DJ1fNTkJ4Y2JlkGjz/aLAmz9EiveK//ur6bzT2JmWFzDlLLQK/JqI0+BeYC3TtNwB8O9N81w4Q81r795Ss1mE7MRnmAeQCLQfoPreW+CQZbx7dNUIpBdQe8+kJXiT+/sZg2Ag8DRdtY7Lr5oYxKBTI/GmP3V1Dcprk6Kq5NidskI5taUWghV93NE/PA8lQhkuOEpbBvAc+qbEAUNRo9r+9NoU37dySQCDidML8iI+MuIytM9alQCWglw/Z5YBzRgMABYWUel5D5Yr27ctQ31BPfReaNVZCXANb9AxHXAombth3qHdQHab6jbtycs3sohzuGEqXndtWclwG9+9d2M42GtPf3KCfrPY21X3q+jEoH0zSv+9pR6tq7q0yXfFgCFQYnfVoa5/55n8M+pju47Sb/t4UG5urlyLs2uoFQHwUqADDfdWx5Slke70M2pog83M1RcjtyWHLirvZWtBIheOVU02Jt4RlFBdRA4cYWf9fE6H6/z8doBXjvAP29V/fv0R+2tbA+AwvBoRUbEK+Nqujzwg0bhsLKOqS6QCOx2wta1ZydAbg1VDgz5gbTbdUt7mX/TqQ6o82kMsAcgt4YuriIizizKWeWQ6YHsCtDruAzdF5keyPRAXi0VW+bABoC8QOwtsXgDBGO/IwHyauiCpd7HG8C4mNsBAMWtFveFgOGrlWb7QibkINBxM0J7NCbvnZcidBe3JQu9d5Ye62DhOtqurcNtrMTLSrzsyObrxzrYkXb2umHstxEgnkoC2K0kgN1KAtitJIDd+h//4oa1H68RnAAAAABJRU5ErkJggg==@@4085f9
     63 | 
    64 | 65 | ### 自定義例子6 - 去除選中連結中的表情漢字並跳轉 66 | 默認是按住Alt鍵劃選,比如h❤ttps://補丁baidu.😀com 67 |
     68 | $text{[^\w\-_\.~!\*'();:@&=\+\$,\/\?#\[\]%]}@@GetLink@@@@@@f9ff9f
     69 | 
    70 | 71 | ### 自定義例子7 - Post 請求 OpenList(原AList)遠程下載 72 |
     73 | p:https://alist.domain.com/api/fs/add_offline_download?path=/115网盘/OpList离线下载&tool=115%20Cloud&delete_policy=delete_on_upload_succeed&urls=["$url"]$headers{"Content-Type": "application/json","Authorization": "alist-50a563b4-and-more-token-chars", "Accept": "*/*", "Host": "alist.domain.com", "Connection": "keep-alive"}@@OpenList@@@@@@df2a11
     74 | 
    75 | 76 | 77 | ### Update 78 | - **`Alt + F9`** 自定義下載,選中文本超鏈則下載文本超鏈,鼠標指向鏈接則下載鏈接,沒有選中則彈框輸入鏈接下載 79 | - 按住 **`Ctrl + Shift`** 點擊批量離線當前頁面中所有資源(如果我給該網盤寫了批量離線功能的話),實際也沒鳥用,度盤批量離線時動不動就網絡繁忙了 80 | - 添加度盤默認下載路徑設置 81 | - 添加網盤設置功能,點擊圖標可設置是否啟用網盤 82 | - 添加網盤排序功能,設置頁面拖拽圖標即可進行排序 83 | - 添加設置項,填入正則表達式可增加支持鏈接,可設置是否僅當鼠標經過時顯示圖標 84 | - 按下 **`F9`** 快速在當前網站禁用或啟用並記錄選擇 85 | - 離線時將32位磁力鏈接轉換為40位磁力鏈接,便於網盤識別動漫花園之類的資源 86 | - 修復百度網盤超級vip問題,感謝Psnowy 87 | 88 | --- 89 | ![img1](https://greasyfork.s3.us-east-2.amazonaws.com/s1beg1iderkn42jq7yl8ogg3z4pr) 90 | 91 | ### 支持服務 92 | * 百度網盤 http://pan.baidu.com 93 | * 115 http://115.com 94 | * Furk http://www.furk.net 95 | * Seedr http://www.seedr.cc 96 | * 迅雷離線 http://lixian.xunlei.com 97 | * Pcloud http://www.pcloud.com 98 | * 小米路由器 http://miwifi.com 99 | * 騰訊微雲 http://weiyun.com 100 | * 九秒雲播 http://apiv.ga 101 | * Torrent.org http://torrent.org.cn 102 | -------------------------------------------------------------------------------- /HacgGodTurn/od.js: -------------------------------------------------------------------------------- 1 | function processTxt(e){var t,r=e;r&&(r=r.replace(regObj.bdshare,linkArr.baidu),r=r.replace(regObj.bdshare1,linkArr.baidu),e=r,r=r.replace(/ *-?本站暂?不再?提供(文件)?下载-? */i,"").replace(/ *保护作者版权 */i,"").replace(/ *请支持正版 */i,"").replace(/\<\!--[^>]*>/g,""),r=/^(magnet|bdcloud) /i.test(r)?r:r.replace(/([a-z0-9]{5,}) +([a-z0-9]{5,})/g,"$1$2"),t=r,r=!/a\shref="magnet:|md5/i.test(r) ?r.replace(regObj.btih,linkArr.btih):r,r=r.replace(regObj.yunpan,linkArr.yunpan),r=r.replace(regObj.howfile,linkArr.howf),r=r.replace(regObj.tcn,linkArr.tcn),r=r.replace(regObj.yyw,linkArr.yyw),r=r.replace(regObj.mega,linkArr.mega),r=r.replace(regObj.pixiv,linkArr.pixiv),r=r.replace(/(baidu\.com\/s\/[a-z\d]{7,23})#([\'\"])/gi,"$1$2"),r=r.replace(regObj.xunlei,linkArr.xunlei));if(t!=r)return r;else return e;}function extCode(e){return text=e.textContent.trim(),simpleRule.test(text)?text.match(simpleRule)[1]:codeRule.test(text)?text.match(codeRule)[1]:""}function seriousReplace(e){var t=document.getElementsByClassName(e);for(var r in t)t[r]&&t[r].innerHTML&&(t[r].innerHTML=t[r].innerHTML.replace(/(\s|^|:|

    |[\u2E80-\u9FFF])(?:https?:\/\/pan\.baidu\.com)?(?:\/?s\/)?(1[0-9a-zA-Z_\-]{6,22})\b(?:\s*(?:)?\s*(?:密码[::]?|pw:|[pP]|提取码?:?)?\s*([a-z0-9A-Z]{4}\b|[^\s,,::\<\>]{2,4})\s*(|<\/p>|$| +))/g,linkArr.baidu).replace(/(\s|^|:|

    |[\u2E80-\u9FFF])(?:https?:\/\/pan\.baidu\.com\/)?(?:\/?s\/)(1[0-9a-zA-Z_\-]{6,22})\b\s*(|<\/p>|$)/g,"$1度娘[$2] $3 ").replace(regObj.yyw,linkArr.yyw).replace(regObj.tcn,linkArr.tcn),t[r].innerHTML = !/a\shref="magnet:|md5/i.test(t[r].innerHTML) ? t[r].innerHTML.replace(regObj.btih, linkArr.btih) : t[r].innerHTML)}function hashFunc(e){return hashWord=e.match(/^\W*/g)[0],e=e.replace(/[\s\W]*/g,"").toUpperCase(),hashStart=e.slice(0,2),hashEnd=e.slice(-2),[hashStart,hashEnd,e,hashWord]}function addInsertHandler(e){var t=!1;document.addEventListener("DOMNodeInserted",function(){if("complete"==document.readyState&&!t){t=!0;var r=0,a=setInterval(function(){1==r?changeUrl(!1,e):2==r&&(t=!1,clearInterval(a)),r++},500)}}),changeUrl(!0,e)}function changeUrl(e,t){for(var r=e?t[0]:["a","img"],a=0,i=r.length;i>a;a++)for(var n=r[a],s=document.querySelectorAll(n),o=0,l=s.length;l>o;o++)for(var p=0,h=t[1].length;h>p;p++){var c=new RegExp(t[1][p][0],"gi");if(n=="a"){c.test(s[o].href) && (s[o].href = s[o].href.replace(c, t[1][p][1]))}else if(n=="img"){c.test(s[o].src) && (s[o].src = s[o].src.replace(c, t[1][p][1]))}else{s[o].parentNode&&c.test(s[o].outerHTML)&&(s[o].outerHTML=s[o].outerHTML.replace(c,t[1][p][1]))}}}var simpleRule=/(?:提取|访问)[码碼]?\s*[::\s]?\s*([a-z\d]{4})/i,codeRule=/(?:(?:提取|钥匙|访问|密[码碼]|艾|Extracted-code|说明|code[::][“"]?)密?[码碼]?[为是]?)\s*[::\s]?\s*([a-z\d]{4}|[^\s,,::]{2,4})(\s|\b|$)/i,regObj={btih:/(?:magnet:\?xt=urn:btih)?((?:[^\/=\|\"]|^)\s*\b)([a-f0-9]{40}|[a-z0-9]{32})\b/gi,bdshare:/(\b|^)(?:b?\/?s\/|.*度.*[::]|BDcloud *|(?:https?:\/\/)?\s*p\s*a\s*n\s*\.\s*b\s*a\s*i\s*d\s*u\s*\.\s*c?\s*o\s*m\s*\/\s*s\s*\/\s*)(1[0-9a-zA-Z_\-]{6,22})\b(?:\s*(?:.*?[::]\s*)?([a-zA-Z0-9]{4}(\b|\s|$)|[^\s,,::\<\>]{2}(\s|$)))?/g,bdshare1:/(^|:|:|\n|BDcloud *)\s*(1[0-9a-zA-Z_\-]{6,22})\b(?:\s*(?:[::\/]\s*)?([a-zA-Z0-9]{4}|[^\s,,::\<\>]{2}))/g,xunlei:/\b(QUF[a-zA-Z0-9\=]+)/g,howfile:/@?(?:HF|howfile)(?:\.com)?\/file\/(\w{4,10})\/(\w{8,})\/?/gi,tcn:/\bt\/(\w{7})/g,yyw:/(\/lb\/)?(5lb[a-zA-Z0-9]{8,12})/g,mega:/(?:https?:\/\/mega)?(?:\.co)?(\.nz\s*\/(#[a-zA-Z0-9_!\-]{22,}(\n[a-zA-Z0-9_!\-]+\n)?))/g,yunpan:/((?:https:\/\/)?yunpan.cn\/([a-zA-Z0-9]+))/g,pixiv:/(?:封面|\s|:|:|^)id[=;](\d+)/gi},linkArr=[];linkArr.btih='$1磁链【种子】 【详情】',linkArr.baidu="$1度娘[$2] $3 ",linkArr.yunpan="云盘:$2",linkArr.howf="好盘:howfile.com/file/$1/$2",linkArr.tcn="短链:t.cn/$1",linkArr.yyw="115礼包:$2 ",linkArr.mega="MEGA网盘\n",linkArr.xunlei="吸血雷",linkArr.pixiv="Pixiv原图";var nod=document.createElement("style"),str=".oD_box{position:fixed;top:60px;right:0px;width:40px;transition: all 0.2s ease;white-space:nowrap;z-index:99998} .oD_box:hover{width:290px} .oD_sel{-ms-transform-origin: 50% 0%;-webkit-transform-origin: 50% 0%;transform-origin: 50% 0%;transform:scale(1.1,1.1);-ms-transform:scale(1.1,1.1);-moz-transform:scale(1.1,1.1);-webkit-transform:scale(1.1,1.1);-o-transform:scale(1.1,1.1);transition: all 1s ease;}";nod.type="text/css",nod.styleSheet?nod.styleSheet.cssText=str:nod.innerHTML=str;var rocketStr='

    ';function elementPosition(o){var t=0,e=0;if(o.offsetParent)for(t=o.offsetLeft,e=o.offsetTop;o.offsetParent;)o=o.offsetParent,t+=o.offsetLeft,e+=o.offsetTop;return{x:t,y:e}}function scrollToControl(o){var t=o;t-=(window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0);var e=t%50,r=(t-e)/50;scrollSmoothly(t,r,o),window.scrollBy(0,e)}function scrollSmoothly(o,t,a){var e=50;return 0>t&&(e=-50),repeatCount`; 28 | downloadBtn.addEventListener("mousedown", e => { 29 | let parent = downloadBtn.parentNode; 30 | if (!parent) return; 31 | simpleClick = false; 32 | let img = parent.querySelector('[data-testid="tweetPhoto"]>img,[data-testid="card.layoutLarge.media"] img'); 33 | if (img) { 34 | let newsrc = img.src.replace("_normal.",".").replace("_200x200.",".").replace("_mini.",".").replace("_bigger.",".").replace(/_x\d+\./,"."), imgname; 35 | if (/\.svg$/.test(newsrc)) return; 36 | if (newsrc == img.src) { 37 | newsrc=newsrc.replace(/\?format=/i, ".").replace(/\&name=/i, ":").replace(/\.(?=[^\.\/]*$)/, "?format=").replace( /(:large|:medium|:small|:orig|:thumb|:[\dx]+)/i, ""); 38 | if (newsrc != img.src) { 39 | newsrc = newsrc + "&name=orig"; 40 | } 41 | } 42 | while(parent) { 43 | if (parent.nodeName == "ARTICLE" && parent.dataset && parent.dataset.testid == "tweet") { 44 | break; 45 | } 46 | parent = parent.parentNode; 47 | } 48 | if (parent) { 49 | const time = parent.querySelector('time[datetime]'); 50 | const user = parent.querySelector('[role="link"]>div>div>span>span'); 51 | let formatMatch = img.src.match(/format=(\w+)/), ext = "jpg"; 52 | if (formatMatch) { 53 | ext = formatMatch[1]; 54 | } else { 55 | formatMatch = newsrc.match(/\.(\w+)/); 56 | if (formatMatch) { 57 | ext = formatMatch[1]; 58 | } 59 | } 60 | imgname = `${user.innerText} ${time.innerText.replace(/(.*) · (.*)/, "$2 $1")}.${ext}`; 61 | } 62 | downloadBtn.href = newsrc; 63 | if ((e.button === 0 && !e.ctrlKey) || touch) { 64 | simpleClick = true; 65 | downloadByFetch(newsrc, imgname); 66 | } 67 | } else { 68 | while(parent) { 69 | if (parent.nodeName == "ARTICLE" && parent.dataset && parent.dataset.testid == "tweet") { 70 | break; 71 | } 72 | parent = parent.parentNode; 73 | } 74 | if (parent) { 75 | downloadBtn.removeAttribute('download'); 76 | let link = parent.querySelector('a[role="link"][aria-label][href^="/"]'); 77 | downloadBtn.href = `https://twitter.luopo.org/?url=${encodeURIComponent(link ? link.href : document.location.href)}`; 78 | if (e.altKey || touch) { 79 | window.open(downloadBtn.href, "_blank"); 80 | } 81 | } 82 | } 83 | }); 84 | downloadBtn.addEventListener("click", e => { 85 | if (simpleClick || e.altKey || touch) { 86 | e.preventDefault(); 87 | e.stopPropagation(); 88 | } 89 | }); 90 | downloadBtn.addEventListener("mouseenter", () => { 91 | downloadBtn.style.opacity = 1; 92 | }); 93 | downloadBtn.addEventListener("mouseleave", () => { 94 | setTimeout(() => { 95 | downloadBtn.style.opacity = 0.1; 96 | }, 100); 97 | }); 98 | async function downloadByFetch(imageUrl, filename) { 99 | try { 100 | const response = await fetch(imageUrl); 101 | if (!response.ok) throw new Error('CORS request failed'); 102 | const blob = await response.blob(); 103 | const blobUrl = URL.createObjectURL(blob); 104 | const tempLink = document.createElement('a'); 105 | tempLink.href = blobUrl; 106 | tempLink.setAttribute('download', filename); 107 | document.body.appendChild(tempLink); 108 | tempLink.click(); 109 | document.body.removeChild(tempLink); 110 | URL.revokeObjectURL(blobUrl); 111 | } catch (error) { 112 | console.error('error:', error); 113 | window.open(imageUrl, '_blank'); 114 | } 115 | } 116 | const show = (ele) => { 117 | ele.appendChild(downloadBtn); 118 | setTimeout(() => { 119 | downloadBtn.style.opacity = touch ? 0.8 : 0.6; 120 | }, 0); 121 | }; 122 | const addBtn = e => { 123 | if (e.target.dataset && e.target.dataset.testid == "card.layoutLarge.media") { 124 | show(e.target.parentNode); 125 | } else if (e.target.dataset && e.target.dataset.testid == "tweetPhoto") { 126 | show(e.target.parentNode); 127 | } else if (e.target.dataset && /^video\-player/.test(e.target.dataset.testid)) { 128 | show(e.target.parentNode); 129 | } else if (e.target.parentNode && e.target.parentNode.dataset && e.target.parentNode.dataset.testid == "tweetPhoto") { 130 | show(e.target.parentNode.parentNode); 131 | } 132 | }; 133 | function isElementVisible(el) { 134 | const rect = el.getBoundingClientRect(); 135 | return rect.top < window.innerHeight && rect.top > 0 && rect.bottom >= 0; 136 | } 137 | function findFirstVisibleElement(selector) { 138 | const elements = document.querySelectorAll(selector); 139 | const firstVisibleElement = Array.from(elements).find(el => { 140 | return isElementVisible(el); 141 | }); 142 | return firstVisibleElement; 143 | } 144 | let checkTimer; 145 | const touchCheck = e => { 146 | clearTimeout(checkTimer); 147 | if (e.target == downloadBtn) return; 148 | checkTimer = setTimeout(() => { 149 | if (isElementVisible(downloadBtn)) return; 150 | let target = findFirstVisibleElement("[data-testid='card.layoutLarge.media']"); 151 | if (target) { 152 | return show(target.parentNode); 153 | } 154 | target = findFirstVisibleElement("[data-testid='tweetPhoto']"); 155 | if (target) { 156 | return show(target.parentNode); 157 | } 158 | target = findFirstVisibleElement("[data-testid^='video-player']"); 159 | if (target) { 160 | return show(target.parentNode); 161 | } 162 | }, 100); 163 | }; 164 | document.addEventListener("mouseenter", addBtn, true); 165 | document.addEventListener("touchstart", e => {touch = true; addBtn(e);}, true); 166 | document.addEventListener("touchend", touchCheck, true); 167 | })(); -------------------------------------------------------------------------------- /DownloadAllContent/DownloadAllContentSavaAsZIP.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name DownloadAllContent ZIP addon 3 | // @name:zh-CN 怠惰小说下载器 ZIP 扩展 4 | // @name:zh-TW 怠惰小説下載器 ZIP 擴充 5 | // @namespace hoothin 6 | // @version 0.6.1 7 | // @description Save content as ZIP for DownloadAllContent 8 | // @description:zh-CN 下载时分章节保存 TXT 并打包为 ZIP 9 | // @description:zh-TW 下載時分章節儲存 TXT 並打包為 ZIP 10 | // @author hoothin 11 | // @match *://*/* 12 | // @grant unsafeWindow 13 | // @grant GM_xmlhttpRequest 14 | // @require https://unpkg.com/jszip@3.7.1/dist/jszip.js 15 | // ==/UserScript== 16 | 17 | (function() { 18 | 'use strict'; 19 | const threadNum = 20;//圖片下載綫程數 20 | const ocrApi = ""; 21 | //const ocrApi = "http://127.0.0.1:416/?img=%t";//ocr 識別 api 22 | var _unsafeWindow = (typeof unsafeWindow == 'undefined') ? window : unsafeWindow; 23 | var zipTips, loadingImgs = [], loadingIndex = 0, loadedNum = 0, ocrNum = 0, zip, blobDict = {}, ocrDict = {}; 24 | 25 | async function dataURLToBlob(dataurl, ext = "jpeg") { 26 | return await new Promise((resolve) => { 27 | if (!dataurl) return resolve(null); 28 | var canvas = document.createElement('CANVAS'); 29 | var ctx = canvas.getContext('2d'); 30 | var img = new Image(); 31 | img.setAttribute("crossOrigin", "anonymous"); 32 | img.onload = function() { 33 | canvas.width = img.width; 34 | canvas.height = img.height; 35 | ctx.drawImage(img, 0, 0); 36 | var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); 37 | for(var i = 0; i < imageData.data.length; i += 4) { 38 | if(imageData.data[i + 3] == 0) { 39 | imageData.data[i] = 255; 40 | imageData.data[i + 1] = 255; 41 | imageData.data[i + 2] = 255; 42 | imageData.data[i + 3] = 255; 43 | } 44 | } 45 | ctx.putImageData(imageData, 0, 0); 46 | canvas.toBlob(blob => { 47 | resolve(blob); 48 | }, `image/${ext}`); 49 | }; 50 | img.onerror = function() { 51 | resolve(null); 52 | }; 53 | img.src = dataurl; 54 | }); 55 | } 56 | 57 | async function blobToDataURL(blob) { 58 | return await new Promise((resolve) => { 59 | var a = new FileReader(); 60 | a.readAsDataURL(blob); 61 | a.onload = function (e) { 62 | resolve(e.target.result); 63 | }; 64 | a.onerror = function (e) { 65 | resolve(null); 66 | }; 67 | }); 68 | } 69 | 70 | async function urlToBlob(url) { 71 | return await new Promise((resolve) => { 72 | GM_xmlhttpRequest({ 73 | method: 'GET', 74 | url: url, 75 | responseType:'blob', 76 | timeout:20000, 77 | headers: { 78 | origin: location.origin, 79 | referer: location.href, 80 | accept: "*/*" 81 | }, 82 | onload: async function(d) { 83 | resolve(d.response); 84 | }, 85 | onerror: function() { 86 | resolve(null); 87 | }, 88 | ontimeout: function() { 89 | resolve(null); 90 | } 91 | }); 92 | }) 93 | } 94 | 95 | async function downloadImage(cb) { 96 | if (loadedNum >= loadingImgs.length || loadingIndex >= loadingImgs.length) return; 97 | let i = loadingIndex; 98 | loadingIndex++; 99 | let src = loadingImgs[i]; 100 | let blob = await urlToBlob(src); 101 | if (blob) { 102 | zip.file("imgs/" + i + ".jpg", blob); 103 | zipTips.innerText = `Download images ${loadedNum + "/" + loadingImgs.length}...`; 104 | blobDict[src] = blob; 105 | } 106 | loadedNum++; 107 | if (loadedNum >= loadingImgs.length) { 108 | if (ocrApi) { 109 | loadingIndex = 0; 110 | let length = Math.min(loadingImgs.length, threadNum); 111 | for (let i = 0; i < length; i++) { 112 | recognizeImage(cb); 113 | } 114 | } else { 115 | cb(); 116 | } 117 | } else downloadImage(cb); 118 | } 119 | 120 | async function recognizeImage(cb) { 121 | if (ocrNum >= loadingImgs.length || loadingIndex >= loadingImgs.length) return; 122 | let i = loadingIndex; 123 | loadingIndex++; 124 | let src = loadingImgs[i]; 125 | let dataURL = await blobToDataURL(blobDict[src]); 126 | let blob = await dataURLToBlob(dataURL, "jpeg"); 127 | dataURL = await blobToDataURL(blob); 128 | let result = await new Promise((resolve) => { 129 | GM_xmlhttpRequest({ 130 | method: 'GET', 131 | url: ocrApi.replace("%t", encodeURIComponent(dataURL.replace("data:image/jpeg;base64,", ""))), 132 | timeout:20000, 133 | onload: function(d) { 134 | resolve(d.response); 135 | }, 136 | onerror: function() { 137 | resolve(null); 138 | }, 139 | ontimeout: function() { 140 | resolve(null); 141 | } 142 | }); 143 | }); 144 | ocrNum++; 145 | zipTips.innerText = `Recognize images ${ocrNum + "/" + loadingImgs.length}...`; 146 | if (result) { 147 | ocrDict[i] = result; 148 | } 149 | if (ocrNum >= loadingImgs.length) { 150 | cb(); 151 | } else recognizeImage(cb); 152 | } 153 | 154 | function downloadImages(cb) { 155 | let length = Math.min(loadingImgs.length, threadNum); 156 | if (length == 0) { 157 | return cb(); 158 | } 159 | for (let i = 0; i < length; i++) { 160 | downloadImage(cb); 161 | } 162 | } 163 | 164 | const mdImgReg = /!\[img\]\((http.+?)\)/; 165 | _unsafeWindow.downloadAllContentSaveAsZip = async (rCats, info, callback) => { 166 | loadingIndex = 0; 167 | loadedNum = 0; 168 | ocrNum = 0; 169 | if (!zipTips) { 170 | zipTips = document.createElement("div"); 171 | } 172 | if (!zipTips.parentNode) { 173 | let txtDownWords = _unsafeWindow.txtDownWords; 174 | if (txtDownWords) { 175 | txtDownWords.appendChild(zipTips); 176 | } 177 | } 178 | console.log("Begin compress to ZIP..."); 179 | zipTips.innerText = "Begin compress to ZIP..."; 180 | zip = new JSZip(); 181 | zip.file("readme.txt", info); 182 | let zipTemp = []; 183 | for (let i = 0; i < rCats.length; i++) { 184 | let cat = rCats[i]; 185 | if (!cat) continue; 186 | let catTitle = cat.match(/.*?\r\n/); 187 | if (!catTitle) continue; 188 | catTitle = catTitle[0].trim(); 189 | cat = cat.replace(catTitle, "").replace(/^[\n\r]+/, ""); 190 | let imgMatch = cat.match(mdImgReg), hasImg = false; 191 | while (imgMatch) { 192 | let index = loadingImgs.indexOf(imgMatch[1]); 193 | if (index == -1) { 194 | index = loadingImgs.length; 195 | loadingImgs.push(imgMatch[1]); 196 | } 197 | cat = cat.replace(imgMatch[0], `![img](imgs/${index}.jpg)`); 198 | imgMatch = cat.match(mdImgReg); 199 | hasImg = true; 200 | } 201 | zipTemp.push({title: catTitle.replace(/[\*\/:<>\?\\\|\r\n]/g, "_").slice(0, 50), hasImg: hasImg, content: cat}); 202 | } 203 | downloadImages(() => { 204 | zipTemp.forEach(d => { 205 | if (ocrApi) { 206 | d.hasImg = false; 207 | Object.keys(ocrDict).forEach(key => { 208 | d.content = d.content.replace(new RegExp(`!\\[img\\]\\(imgs/${key}\\.jpg\\)`, 'g'), ocrDict[key]); 209 | }); 210 | } 211 | zip.file(d.title + (d.hasImg ? ".md" : ".txt"), d.content); 212 | }); 213 | zip.generateAsync({type: "blob", compression: "DEFLATE"}, meta => {zipTips.innerText = "percent: " + ((meta && meta.percent && meta.percent.toFixed(2)) || "100") + "%"}).then(function(content){ 214 | callback(content); 215 | zipTips.innerText = ""; 216 | }) 217 | }); 218 | } 219 | })(); -------------------------------------------------------------------------------- /True URL downloads/manageLinks.js: -------------------------------------------------------------------------------- 1 | /* 2 | manageLinks v0.1 3 | https://github.com/hoothin/UserScripts/tree/master/True%20URL%20downloads/managerLinks.js 4 | (c) 2017-2017 by Hoothin Wang. All rights reserved. 5 | */ 6 | var specialUrl = /^thunder|^magnet|^ed2k/i, 7 | simplefilter = /\.php|\.htm|\.jsp|\.asp|\/[^\.]+$/i, 8 | resReg = /.*(^thunder|^magnet|^ed2k|\.torrent$|\.mp4$|\.rar$|\.7z$|\.zip$|\.rmvb$|\.mkv$|\.avi$|\.iso$|\.mp3$|\.txt$|\.exe$|\.chm$|\.pdf$|\.ppt$|\.doc$|\.pptx$|\.docx$|\.epub$|\.xlsx$|\.xls$|\.flac$|\.wma$|\.wav$|\.aac$|\.ape$|\.mid$|\.ogg$|\.m4a$|\.dts$|\.dsd$|\.apk$|\.flv$).*/i, 9 | linksArr = [],frame,linkPair = {},customReg, 10 | lang = { 11 | copyAll : "全部复制", 12 | copySel : "复制选中", 13 | addTips : "%i代表递增 %n代表文件名", 14 | sortByName : "按文件名排序", 15 | sortByUrl : "按网址排序", 16 | sortByType : "按扩展名排序", 17 | preHolder : "批量前缀", 18 | nextHolder : "批量后缀", 19 | closeBtn : "关闭", 20 | typeHead : "类型:" 21 | }; 22 | 23 | var by = function(byName, secName) { 24 | var compare = function(o, p, name) { 25 | var a, b; 26 | if (typeof o === "object" && typeof p === "object" && o && p) { 27 | a = o[name]; 28 | b = p[name]; 29 | if (a === b) { 30 | return 0; 31 | } 32 | if (typeof a === typeof b) { 33 | return a < b ? -1 : 1; 34 | } 35 | return typeof a < typeof b ? -1 : 1; 36 | } else { 37 | throw("error"); 38 | } 39 | } 40 | return function(o, p) { 41 | var result = compare(o, p, byName); 42 | if (secName && result == 0) { 43 | result = compare(o, p, secName); 44 | } 45 | return result; 46 | } 47 | } 48 | 49 | if (!Array.prototype.indexOf) { 50 | Array.prototype.indexOf = function (item) { 51 | var index = -1; 52 | for (var i = 0, length = this.length; i < length; i++) { 53 | if (this[i] == item) { 54 | index = i; 55 | } 56 | } 57 | return index; 58 | }; 59 | } 60 | 61 | function getLinks() { 62 | [].forEach.call(document.querySelectorAll('a'), function(link){ 63 | if (link.className != "whx-a" && ((customReg && customReg.test(link.href)) || specialUrl.test(link.href) || (!simplefilter.test(link.href) && resReg.test(link.href))) && linksArr.indexOf(link.href) == -1) { 64 | linksArr.push(link.href); 65 | linkPair[link.href]=link; 66 | } 67 | }); 68 | [].forEach.call(document.querySelectorAll('source'), function(link){ 69 | if (((customReg && customReg.test(link.href)) || specialUrl.test(link.href) || (!simplefilter.test(link.href) && resReg.test(link.href))) && linksArr.indexOf(link.src) == -1) { 70 | linksArr.push(link.src); 71 | linkPair[link.href]=link; 72 | } 73 | }); 74 | } 75 | 76 | function initLang(l){ 77 | if (!l) return; 78 | lang = l; 79 | } 80 | 81 | function setLinkCustomReg(r){ 82 | customReg = r; 83 | } 84 | 85 | function showLinkFrame(callBack) { 86 | var linkItems = []; 87 | var typeHtml = lang.typeHead+" "; 88 | if (!frame) { 89 | $('').appendTo('head'); 90 | frame = $(``); 103 | $(document.body).append(frame); 104 | $("#managerLinksSortByName").click(function() { 105 | $("#managerLinksLinks").html(""); 106 | linkItems.sort(by("linkName", "href")); 107 | linkItems.forEach(function(item) { 108 | $("#managerLinksLinks").append(item.item); 109 | }); 110 | }); 111 | $("#managerLinksSortByUrl").click(function() { 112 | $("#managerLinksLinks").html(""); 113 | linkItems.sort(by("href", "type")); 114 | linkItems.forEach(function(item) { 115 | $("#managerLinksLinks").append(item.item); 116 | }); 117 | }); 118 | $("#managerLinksSortByType").click(function() { 119 | $("#managerLinksLinks").html(""); 120 | linkItems.sort(by("type", "href")); 121 | linkItems.forEach(function(item) { 122 | $("#managerLinksLinks").append(item.item); 123 | }); 124 | }); 125 | $("#managerLinksCopyAll").click(function() { 126 | var pre = $("#managerLinksPre").val(); 127 | var after = $("#managerLinksAfter").val(); 128 | var resultStr = "",i=0; 129 | linkItems.forEach(function(item) { 130 | i++; 131 | var linkName = decodeURIComponent(item.linkName); 132 | resultStr += (pre.replace(/%i/g,i+"").replace(/%n/g,linkName) + item.href + after.replace(/%i/g,i+"").replace(/%n/g,linkName) + "\n"); 133 | }); 134 | callBack(resultStr); 135 | }); 136 | $("#managerLinksCopySel").click(function() { 137 | var pre = $("#managerLinksPre").val(); 138 | var after = $("#managerLinksAfter").val(); 139 | var resultStr = "",i=0; 140 | linkItems.forEach(function(item) { 141 | i++; 142 | if (item.item.children("input")[0].checked) { 143 | var linkName = decodeURIComponent(item.linkName); 144 | resultStr += (pre.replace(/%i/g,i+"").replace(/%n/g,linkName) + item.href + after.replace(/%i/g,i+"").replace(/%n/g,linkName) + "\n"); 145 | } 146 | }); 147 | if(resultStr != "") 148 | callBack(resultStr); 149 | }); 150 | $("#managerLinksClose").click(function() { 151 | frame.hide(); 152 | }); 153 | $("#managerLinksContent>div")[0].onclick = function() { 154 | frame.hide(); 155 | }; 156 | } 157 | getLinks(); 158 | if(linksArr.length == 0){ 159 | callBack(); 160 | return; 161 | } 162 | $("#managerLinksLinks").html(""); 163 | linksArr.forEach(function(link) { 164 | var type; 165 | if(resReg.test(link)){ 166 | type = link.replace(resReg, "$1"); 167 | }else{ 168 | type = link; 169 | let matchArr = link.match(customReg); 170 | if(matchArr){ 171 | type = matchArr[1] || matchArr[0]; 172 | } 173 | if(type && type.length > 10){ 174 | type = type.substr(0, 10); 175 | } 176 | } 177 | var linkName = linkPair[link].innerText; 178 | if (linkName) linkName = linkName.trim(); 179 | if (!linkName) linkName = type.indexOf(".") == -1 ? link : link.replace(/.*\/([^\/]+)$/i, "$1"); 180 | if (typeHtml.indexOf(type) == -1) { 181 | typeHtml += '' + type + " "; 182 | } 183 | var linkItem = $(''); 184 | $("#managerLinksLinks").append(linkItem); 185 | linkItems.push({ 186 | item: linkItem, 187 | href: link, 188 | type: type, 189 | linkName: linkName 190 | }); 191 | }); 192 | $("#managerLinksType").html(typeHtml); 193 | $("#managerLinksType>a").click(function(e) { 194 | var selected = this.style.textDecoration == "underline"; 195 | this.style.textDecoration = selected ? "" : "underline"; 196 | var type = this.innerHTML; 197 | linkItems.forEach(function(item) { 198 | if (item.type == type) { 199 | item.item.children("input")[0].checked = !selected; 200 | } 201 | }); 202 | }); 203 | frame.show(); 204 | $("#managerLinksLinks").height($(".managerLinksBody").height() - $("#managerLinksType").height() - $("#managerLinksSortByName").height() * 3 - 38); 205 | $(".managerLinksBody").hide(); 206 | $(".managerLinksBody").show(); 207 | $(".managerLinksBody").css('margin-top',-$(".managerLinksBody").height() / 2); 208 | } -------------------------------------------------------------------------------- /Picviewer CE+/README.md: -------------------------------------------------------------------------------- 1 | # 🏞️ Picviewer CE+ 2 | 3 | [![twitter](https://img.shields.io/twitter/follow/HoothinDev)](https://twitter.com/intent/follow?screen_name=HoothinDev) [![Discord](https://img.shields.io/badge/Discord-Join-blue.svg?logo=discord&style=social)](https://discord.com/invite/keqypXC6wD) [![reddit](https://img.shields.io/reddit/subreddit-subscribers/PicviewerCE)](https://www.reddit.com/r/PicviewerCE) [![stars](https://img.shields.io/github/stars/Hoothin/UserScripts)](https://github.com/hoothin/UserScripts#StarMe) 4 | 5 | ### Zoom images across all your favorite websites. Pop up, scale, edit, rotate, batch save images, or automatically load pictures from subsequent pages. Simply hover your mouse over any image and click the icons on the float bar. 6 | 7 | + **Adjust:** Scale/rotate/batch save every picture 8 | 9 | + **View:** Find and popup large version for pictures with click or mouse over 10 | 11 | + **Fetch:** Auto load and parse next paginated web 12 | pages and show ALL pics 13 | 14 | + **Download:** Pictures export to page or package into ZIP 15 | 16 | + **Search:** Search similar image by picture 17 | 18 | + View long image by scroll 19 | 20 | Recommended similar plugins: [Imagus](https://chromewebstore.google.com/detail/imagus/immpkjjlgappgfkkfieppnmlhakdmaab) - [Hover-zoom+](https://chromewebstore.google.com/detail/hover-zoom+/pccckmaobkjjboncdfnnofkonhgpceea) - [Mouseover Popup Image Viewer](https://greasyfork.org/scripts/394820) 21 | 22 | ## Quick Start 23 | 24 | Install from [Github📥](https://hoothin.github.io/UserScripts/Picviewer%20CE+/dist.user.js) or [Greasefork📥](https://greasyfork.org/scripts/24204-picviewer-ce). 25 | 26 | Hover your mouse over any image and click the icons on the float bar. 27 | 28 | Press `CTRL + G` to quickly enter the gallery. Hold `CTRL` to view a larger picture when hovering over images or links. 29 | 30 | There are additional settings available in the "Picviewer CE+ config" for further customization. Currently, reviewing these settings is the best way to learn about the script's capabilities. Try exploring more functions on your own! 31 | 32 | ## Contribution & Support 33 | 34 | If you are glad to assist with the translation, please ✍️[edit this file](https://github.com/hoothin/UserScripts/edit/master/Picviewer%20CE%2B/pvcep_lang.js#L1). It will be beneficial for individuals who speak the same language as you do. Thank you for your help. 35 | 36 | + English by [RX-3200](https://greasyfork.org/users/43-rx-3200). 37 | 38 | + Português by [AstroCoelestis](https://greasyfork.org/users/881248). 39 | 40 | + Русский by RX-3200 & vanja-san. 41 | 42 | + Turkish by [PUFF1N](https://github.com/PUFF1N-000). 43 | 44 | + Ukrainian by [MaSHiNiK](https://github.com/MaSHiNiK). 45 | 46 | + Arabic by [Prankster 199](https://github.com/vfggf95565). 47 | 48 | *Need more rules for peculiar sites? feel free to pull requests or open issues.* 49 | 50 | ## PDF Addon 51 | Picviewer CE+ [PDF Addon](https://hoothin.github.io/UserScripts/Picviewer%20CE+/pvcep_pdf_addon.user.js). After installing this addon, when the `Compress to ZIP` feature is enabled, a PDF file will be generated instead of a ZIP file during the packaging process. 52 | 53 |
    54 | Make a PDF e-book with this addon 55 |

    For example, if there is a website with images from xxx.com/1.jpg to xxx.com/99.jpg, you can use this addon to generate a beautiful PDF e-book as follows:

    56 |
      57 |
    1. Open the gallery by pressing Ctrl + g
    2. 58 |
    3. In the Command menu, find and click Add image
    4. 59 |
    5. Input xxx.com/[1-99].jpg
    6. 60 |
    7. Right-click in the thumbnail frame below to ignore any unwanted images
    8. 61 |
    9. Click Download all shown in the Command menu
    10. 62 |
    63 |

    This way, you'll get a beautifully created PDF e-book.

    64 |
    65 | 66 | ## Custom [Rules Example](pvcep_rules.js): 67 | **💝 Buy me a coffee with [Ko-fi](https://ko-fi.com/hoothin) or [愛發電](https://afdian.com/a/hoothin) to keep my scripts always up to date.** 68 | 69 | 70 | 71 | + Match image src(no matter which site) with /pics\\.dmm\\.co\\.jp/i and replace image url from "ps.jpg" to "pl.jpg" 72 | 73 | ``` json 74 | { 75 | "name": "Dmm", 76 | "src": "pics\\.dmm\\.co\\.jp", 77 | "r": "ps.jpg", 78 | "s": "pl.jpg" 79 | } 80 | ``` 81 | + Match site with /xxx\.com/ and replace image url from /us\\.xxx\\.com/\d+wm\//i to "previews.xxx.com/images/" 82 | 83 | ``` json 84 | { 85 | "name": "Example", 86 | "url": "^https://xxx\\.com/", 87 | "r": "/us\\.xxx\\.com/\\d+wm//i", 88 | "s": "previews.xxx.com/images/" 89 | } 90 | ``` 91 | + Add click-to-open for existing asiansister rule. 92 | 93 | ``` json 94 | { 95 | "name": "Asiansister", 96 | "clickToOpen": { 97 | "enabled": true, 98 | "preventDefault": true, 99 | "type": "actual", 100 | "button": 0, 101 | "alt": false, 102 | "ctrl": false, 103 | "shift": false, 104 | "meta": false 105 | } 106 | } 107 | ``` 108 | You have the option to use a standalone userscript, which allows you to manage all of your custom rules effectively. 109 | 110 | Feel free to share your own custom rules on Greasy Fork! 111 | 112 | ``` js 113 | // ==UserScript== 114 | // @name Picviewer CE+ custom rules 115 | // @namespace hoothin 116 | // @version 0.1 117 | // @description Picviewer CE+ custom rules 118 | // @author You 119 | // @match *://*/* 120 | // @run-at document-start 121 | // @grant none 122 | // ==/UserScript== 123 | 124 | (function() { 125 | 'use strict'; 126 | window.pvcepRules = (window.pvcepRules || []).concat([ 127 | //Delete these two example rules and add your own. 128 | { 129 | name: "rule1", 130 | src: /pics\.dmm\.co\.jp/i, 131 | r: "ps.jpg", 132 | s: "pl.jpg" 133 | }, 134 | { 135 | name: "rule2", 136 | url: /^https:\/\/xxx\.com\//, 137 | r: /us\.xxx\.com\/\d+wm\//i, 138 | s: "previews.xxx.com/images/" 139 | } 140 | ]); 141 | })(); 142 | ``` 143 | 144 | 145 |
    146 | Advance rule wizard 147 |

    There are two types of rules available:

    148 |
      149 |
    • 150 |

      JSON (simple mode)

      151 |

      These rules are written in JSON format and can be imported online through Discussions or Reddit. 152 | They won't limited by websites that have a strict Content Security Policy that disallows unsafe-eval.

      153 |
        154 |
      • JSON params 155 |
          156 |
        • 157 |

          name

          158 |

          "name": "rule name"

          159 |

          Name of the rule

          160 |
        • 161 |
        • 162 |

          url

          163 |

          "url": "^https://google\\.com"

          164 |

          Regular expression used to match the site URL.

          165 |
        • 166 |
        • 167 |

          src

          168 |

          "src": "^https://image\\.xx\\.com"

          169 |

          Regular expression used to match the image src

          170 |
        • 171 |
        • 172 |

          r

          173 |

          "r": "/(.*)\\d+/i" or "r": "thumb"

          174 |

          Simple string or regular expression used to replace the image src from

          175 |
        • 176 |
        • 177 |

          s

          178 |

          "s": "$1"

          179 |

          Replace the image src to

          180 |
        • 181 |
        • 182 |

          ext

          183 |

          "ext": "previous"

          184 |

          Capture nearby image element when the mouse hovers over a non-image element.

          185 |
        • 186 |
        • 187 |

          lazyAttr

          188 |

          "lazyAttr": "data-lazy"

          189 |

          Lazy loaded original image URL attribute name

          190 |
        • 191 |
        • 192 |

          xhr

          193 |

          "xhr": { "url": ".showcase__link", "query": "img[fetchpriority]" }

          194 |

          Fetch the link above the image that matches ".showcase__link" and query the "img[fetchpriority]" on the inner page from the link.

          195 |
        • 196 |
        197 |
      • 198 |
      199 |
    • 200 |
    • 201 |

      JS (full mode)

      202 |

      These rules are written in JavaScript object format. If you are not using a standalone userscript, they may be limited by websites that have a strict Content Security Policy that disallows unsafe-eval.

      203 |
        204 |
      • JS params 205 |
          206 |
        • all mentioned above and the function type instead of string type
        • 207 |
        • getImage
        • 208 |
        • getExtSrc
        • 209 |
        210 |
      • 211 |
      212 |

      Learn from https://github.com/hoothin/UserScripts/blob/master/Picviewer%20CE%2B/pvcep_rules.js

      213 |
    • 214 |
    215 |
    216 | 217 | ## Blank Gallery Page 218 | [https://hoothin.github.io/UserScripts/Picviewer%20CE+/gallery.html](https://hoothin.github.io/UserScripts/Picviewer%20CE+/gallery.html) 219 | 220 | > *A blank gallery page designed for viewing local or online pictures, showcasing every image you have imported.* 221 | 222 | You can drag and drop **folders** or videos/audios/images into this gallery to get an electronic slideshow to view them. 223 | 224 | Click with `Ctrl key` can import folder too. 225 | 226 | Include `mode=`*`1`* to open gallery in view-more mode.
    227 | Add `imgs=`*`http://xxx/xxx.jpg`* to import images. ` ` to split multi-image, `[01-09]` to generate nine urls form 01 to 09
    228 | For example: 229 | ```url 230 | https://hoothin.github.io/UserScripts/Picviewer%20CE+/gallery.html?mode=0&imgs=http://xxx/xxx[01-99].jpg 231 | or 232 | https://hoothin.github.io/UserScripts/Picviewer%20CE+/gallery.html?mode=0&imgs=${encodeURIComponent(IMG1 + ' ' + IMG2)} 233 | ``` 234 | 235 | 236 | 237 | ## Thousands compatible sites for find larger or original images like 238 | 239 | deviantart.com 240 | google.com 241 | wikipedia.org 242 | dribbble.com 243 | bing.com 244 | imdb.com 245 | github.com 246 | tumblr.com 247 | youtube.com 248 | pixiv.net 249 | steampowered.com 250 | itunes.apple.com 251 | pinterest.com 252 | gelbooru.com 253 | discordapp.com 254 | twitter.com 255 | fandom.com 256 | reddit.com 257 | yande.re 258 | wallhaven.cc 259 | 500px 260 | nyaa 261 | e621.net 262 | nhentai.net 263 | tieba.baidu.com 264 | douban.com 265 | weibo.com 266 | bilibili.com 267 | t.qq.com 268 | huaban.com 269 | hujiang.com 270 | dianping.com 271 | trakt.tv 272 | music.163.com 273 | rule34hentai.net 274 | photosight.ru 275 | boqingguan.com 276 | 178.com 277 | zhisheji.com 278 | themex.net 279 | operachina.com 280 | topit.me 281 | bcy.net 282 | zhihu.com 283 | autohome.com.cn 284 | bitauto.com 285 | xcar.com.cn 286 | pcauto.com.cn 287 | auto.sina.com.cn 288 | baike.baidu.com 289 | nvshens.com 290 | 24meitu.com 291 | acgget.com 292 | lofter.com 293 | sohu.com 294 | taobao.com 295 | alibaba.com 296 | yihaodian.com 297 | addons.mozilla.org 298 | crsky.com 299 | firefox.net.cn 300 | jd.com 301 | dangdang.com 302 | detail.zol.com.cn 303 | duokan.com 304 | youku.com 305 | yyets.com 306 | xiaohongshu.com 307 | moegirl.org 308 | fanfou.com 309 | meipai.com 310 | game.yesky.com 311 | dota2.sgamer.com 312 | mafengwo.cn 313 | 588ku.com 314 | ibaotu.com 315 | 58pic.com 316 | 317 | And so on ... 318 | -------------------------------------------------------------------------------- /BingBgForBaidu/BingBgForGoogle.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name BingBgForGoogle 3 | // @name:zh-CN 谷Bing图 4 | // @name:zh-TW 谷Bing圖 5 | // @namespace hoothin 6 | // @version 0.3 7 | // @description Just change the background image of Google homepage to Bing 8 | // @description:zh-CN 给谷歌首页换上 Bing 的背景图 9 | // @description:zh-TW 給 Google 首頁換上 Bing 的背景圖 10 | // @author hoothin 11 | // @grant GM_xmlhttpRequest 12 | // @grant GM_setValue 13 | // @grant GM_getValue 14 | // @grant GM_addStyle 15 | // @grant GM_registerMenuCommand 16 | // @grant unsafeWindow 17 | // @connect global.bing.com 18 | // @connect cn.bing.com 19 | // @license MIT License 20 | // @match *://www.google.com/* 21 | // @match *://www.google.ad/* 22 | // @match *://www.google.ae/* 23 | // @match *://www.google.com.af/* 24 | // @match *://www.google.com.ag/* 25 | // @match *://www.google.al/* 26 | // @match *://www.google.am/* 27 | // @match *://www.google.co.ao/* 28 | // @match *://www.google.com.ar/* 29 | // @match *://www.google.as/* 30 | // @match *://www.google.at/* 31 | // @match *://www.google.com.au/* 32 | // @match *://www.google.az/* 33 | // @match *://www.google.ba/* 34 | // @match *://www.google.com.bd/* 35 | // @match *://www.google.be/* 36 | // @match *://www.google.bf/* 37 | // @match *://www.google.bg/* 38 | // @match *://www.google.com.bh/* 39 | // @match *://www.google.bi/* 40 | // @match *://www.google.bj/* 41 | // @match *://www.google.com.bn/* 42 | // @match *://www.google.com.bo/* 43 | // @match *://www.google.com.br/* 44 | // @match *://www.google.bs/* 45 | // @match *://www.google.bt/* 46 | // @match *://www.google.co.bw/* 47 | // @match *://www.google.by/* 48 | // @match *://www.google.com.bz/* 49 | // @match *://www.google.ca/* 50 | // @match *://www.google.cd/* 51 | // @match *://www.google.cf/* 52 | // @match *://www.google.cg/* 53 | // @match *://www.google.ch/* 54 | // @match *://www.google.ci/* 55 | // @match *://www.google.co.ck/* 56 | // @match *://www.google.cl/* 57 | // @match *://www.google.cm/* 58 | // @match *://www.google.cn/* 59 | // @match *://www.google.com.co/* 60 | // @match *://www.google.co.cr/* 61 | // @match *://www.google.com.cu/* 62 | // @match *://www.google.cv/* 63 | // @match *://www.google.com.cy/* 64 | // @match *://www.google.cz/* 65 | // @match *://www.google.de/* 66 | // @match *://www.google.dj/* 67 | // @match *://www.google.dk/* 68 | // @match *://www.google.dm/* 69 | // @match *://www.google.com.do/* 70 | // @match *://www.google.dz/* 71 | // @match *://www.google.com.ec/* 72 | // @match *://www.google.ee/* 73 | // @match *://www.google.com.eg/* 74 | // @match *://www.google.es/* 75 | // @match *://www.google.com.et/* 76 | // @match *://www.google.fi/* 77 | // @match *://www.google.com.fj/* 78 | // @match *://www.google.fm/* 79 | // @match *://www.google.fr/* 80 | // @match *://www.google.ga/* 81 | // @match *://www.google.ge/* 82 | // @match *://www.google.gg/* 83 | // @match *://www.google.com.gh/* 84 | // @match *://www.google.com.gi/* 85 | // @match *://www.google.gl/* 86 | // @match *://www.google.gm/* 87 | // @match *://www.google.gr/* 88 | // @match *://www.google.com.gt/* 89 | // @match *://www.google.gy/* 90 | // @match *://www.google.com.hk/* 91 | // @match *://www.google.hn/* 92 | // @match *://www.google.hr/* 93 | // @match *://www.google.ht/* 94 | // @match *://www.google.hu/* 95 | // @match *://www.google.co.id/* 96 | // @match *://www.google.ie/* 97 | // @match *://www.google.co.il/* 98 | // @match *://www.google.im/* 99 | // @match *://www.google.co.in/* 100 | // @match *://www.google.iq/* 101 | // @match *://www.google.is/* 102 | // @match *://www.google.it/* 103 | // @match *://www.google.je/* 104 | // @match *://www.google.com.jm/* 105 | // @match *://www.google.jo/* 106 | // @match *://www.google.co.jp/* 107 | // @match *://www.google.co.ke/* 108 | // @match *://www.google.com.kh/* 109 | // @match *://www.google.ki/* 110 | // @match *://www.google.kg/* 111 | // @match *://www.google.co.kr/* 112 | // @match *://www.google.com.kw/* 113 | // @match *://www.google.kz/* 114 | // @match *://www.google.la/* 115 | // @match *://www.google.com.lb/* 116 | // @match *://www.google.li/* 117 | // @match *://www.google.lk/* 118 | // @match *://www.google.co.ls/* 119 | // @match *://www.google.lt/* 120 | // @match *://www.google.lu/* 121 | // @match *://www.google.lv/* 122 | // @match *://www.google.com.ly/* 123 | // @match *://www.google.co.ma/* 124 | // @match *://www.google.md/* 125 | // @match *://www.google.me/* 126 | // @match *://www.google.mg/* 127 | // @match *://www.google.mk/* 128 | // @match *://www.google.ml/* 129 | // @match *://www.google.com.mm/* 130 | // @match *://www.google.mn/* 131 | // @match *://www.google.com.mt/* 132 | // @match *://www.google.mu/* 133 | // @match *://www.google.mv/* 134 | // @match *://www.google.mw/* 135 | // @match *://www.google.com.mx/* 136 | // @match *://www.google.com.my/* 137 | // @match *://www.google.co.mz/* 138 | // @match *://www.google.com.na/* 139 | // @match *://www.google.com.ng/* 140 | // @match *://www.google.com.ni/* 141 | // @match *://www.google.ne/* 142 | // @match *://www.google.nl/* 143 | // @match *://www.google.no/* 144 | // @match *://www.google.com.np/* 145 | // @match *://www.google.nr/* 146 | // @match *://www.google.nu/* 147 | // @match *://www.google.co.nz/* 148 | // @match *://www.google.com.om/* 149 | // @match *://www.google.com.pa/* 150 | // @match *://www.google.com.pe/* 151 | // @match *://www.google.com.pg/* 152 | // @match *://www.google.com.ph/* 153 | // @match *://www.google.com.pk/* 154 | // @match *://www.google.pl/* 155 | // @match *://www.google.pn/* 156 | // @match *://www.google.com.pr/* 157 | // @match *://www.google.ps/* 158 | // @match *://www.google.pt/* 159 | // @match *://www.google.com.py/* 160 | // @match *://www.google.com.qa/* 161 | // @match *://www.google.ro/* 162 | // @match *://www.google.ru/* 163 | // @match *://www.google.rw/* 164 | // @match *://www.google.com.sa/* 165 | // @match *://www.google.com.sb/* 166 | // @match *://www.google.sc/* 167 | // @match *://www.google.se/* 168 | // @match *://www.google.com.sg/* 169 | // @match *://www.google.sh/* 170 | // @match *://www.google.si/* 171 | // @match *://www.google.sk/* 172 | // @match *://www.google.com.sl/* 173 | // @match *://www.google.sn/* 174 | // @match *://www.google.so/* 175 | // @match *://www.google.sm/* 176 | // @match *://www.google.sr/* 177 | // @match *://www.google.st/* 178 | // @match *://www.google.com.sv/* 179 | // @match *://www.google.td/* 180 | // @match *://www.google.tg/* 181 | // @match *://www.google.co.th/* 182 | // @match *://www.google.com.tj/* 183 | // @match *://www.google.tl/* 184 | // @match *://www.google.tm/* 185 | // @match *://www.google.tn/* 186 | // @match *://www.google.to/* 187 | // @match *://www.google.com.tr/* 188 | // @match *://www.google.tt/* 189 | // @match *://www.google.com.tw/* 190 | // @match *://www.google.co.tz/* 191 | // @match *://www.google.com.ua/* 192 | // @match *://www.google.co.ug/* 193 | // @match *://www.google.co.uk/* 194 | // @match *://www.google.com.uy/* 195 | // @match *://www.google.co.uz/* 196 | // @match *://www.google.com.vc/* 197 | // @match *://www.google.co.ve/* 198 | // @match *://www.google.co.vi/* 199 | // @match *://www.google.com.vn/* 200 | // @match *://www.google.vu/* 201 | // @match *://www.google.ws/* 202 | // @match *://www.google.rs/* 203 | // @match *://www.google.co.za/* 204 | // @match *://www.google.co.zm/* 205 | // @match *://www.google.co.zw/* 206 | // @match *://www.google.cat/* 207 | // @downloadURL https://update.greasyfork.org/scripts/503741/BingBgForGoogle.user.js 208 | // @updateURL https://update.greasyfork.org/scripts/503741/BingBgForGoogle.meta.js 209 | // ==/UserScript== 210 | 211 | (function() { 212 | 'use strict'; 213 | if (/\?q=/.test(location.href)) return; 214 | let LinkPa = document.querySelector("[data-ogbl]"); 215 | if (!LinkPa) return; 216 | let bingBgLink = document.createElement("a"); 217 | bingBgLink.className = LinkPa.firstChild.firstChild.className; 218 | bingBgLink.target = "_blank"; 219 | bingBgLink.innerText = "Bing Bg"; 220 | let linkDiv = document.createElement("div"); 221 | linkDiv.className = LinkPa.firstChild.className; 222 | linkDiv.appendChild(bingBgLink); 223 | LinkPa.appendChild(linkDiv); 224 | let skinContainer = document.body; 225 | GM_addStyle(` 226 | body{ 227 | background-position: center 0; 228 | background-repeat: no-repeat; 229 | background-size: cover; 230 | -webkit-background-size: cover; 231 | -o-background-size: cover; 232 | } 233 | #gb{ 234 | background-color: unset!important; 235 | } 236 | [role="navigation"],[role="contentinfo"]{ 237 | background-color: rgb(32 33 36 / 50%)!important; 238 | } 239 | #gb *,[role="contentinfo"] *{ 240 | color: white!important; 241 | } 242 | `); 243 | 244 | let btnK = document.querySelector("input[name='btnK']"); 245 | let clickHandler = e => { 246 | skinContainer.style.backgroundImage = ""; 247 | }; 248 | btnK.addEventListener("click",clickHandler); 249 | let bingImgObj = GM_getValue("bingImgObj"); 250 | if (bingImgObj) { 251 | skinContainer.style.backgroundImage = "url(\"" + bingImgObj.base64 + "\")"; 252 | } 253 | 254 | GM_xmlhttpRequest({ 255 | method: 'GET', 256 | url: "https://global.bing.com/HPImageArchive.aspx?format=js&idx=0&pid=hp&video=1&n=1", 257 | onload: function(result) { 258 | let jsonData = null; 259 | try { 260 | jsonData = JSON.parse(result.responseText); 261 | let bgUrl = jsonData.images[0].url; 262 | if (!/^https?:\/\//.test(bgUrl)) { 263 | bgUrl = "https://global.bing.com" + bgUrl; 264 | } 265 | bingBgLink.title = jsonData.images[0].copyright; 266 | bingBgLink.href = bgUrl; 267 | if (bingImgObj && bingImgObj.url == bgUrl) return; 268 | if (!bingImgObj) skinContainer.style.backgroundImage = "url(\"" + bgUrl + "\")"; 269 | GM_xmlhttpRequest({ 270 | method: 'GET', 271 | url: bgUrl, 272 | responseType: "blob", 273 | onload: function(r) { 274 | let blob = r.response; 275 | let fr = new FileReader(); 276 | fr.readAsDataURL(blob); 277 | fr.onload = function (e) { 278 | let base64ImgData = e.target.result; 279 | GM_setValue("bingImgObj",{url: bgUrl, base64: base64ImgData}); 280 | }; 281 | } 282 | }); 283 | } catch (e) { 284 | console.log(e); 285 | } 286 | } 287 | }); 288 | let blurStyle; 289 | function createBlur() { 290 | if (!blurStyle) { 291 | blurStyle = document.createElement("style"); 292 | blurStyle.innerText = ` 293 | body::before{ 294 | content: " "; 295 | display: block; 296 | position: absolute; 297 | left: 0; 298 | top: 0; 299 | right: 0; 300 | bottom: 0; 301 | background: inherit; 302 | filter: blur(5px); 303 | z-index: -1; 304 | }`; 305 | } 306 | document.head.appendChild(blurStyle); 307 | } 308 | if (GM_getValue("blur")) { 309 | createBlur(); 310 | } 311 | GM_registerMenuCommand("Change blur", () => { 312 | if (blurStyle && blurStyle.parentNode) { 313 | GM_setValue("blur", false); 314 | blurStyle.parentNode.removeChild(blurStyle); 315 | } else { 316 | GM_setValue("blur", true); 317 | createBlur(); 318 | } 319 | }); 320 | })(); -------------------------------------------------------------------------------- /Easy offline/Easy offline pikpak.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Easy Offline pikpak addon 3 | // @namespace hoothin 4 | // @version 2024-08-16 5 | // @description Add pikpak support for Easy Offline 6 | // @author hoothin 7 | // @match *://*/* 8 | // @grant GM_setValue 9 | // @grant GM_getValue 10 | // @grant GM_xmlhttpRequest 11 | // @grant GM_notification 12 | // @grant unsafeWindow 13 | // @run-at document-start 14 | // @require https://unpkg.com/crypto-js@4.2.0/crypto-js.js 15 | // @connect user.mypikpak.com 16 | // @connect api-drive.mypikpak.com 17 | // ==/UserScript== 18 | 19 | (function() { 20 | 'use strict'; 21 | let info = GM_getValue("pikpakUserInfo"), device_id, user_id; 22 | const CLIENT_ID = "YNxT9w7GMdWvEOKa"; 23 | const CLIENT_SECRET = "dbw2OtmVEeuUvIptb1Coyg"; 24 | const CLIENT_VERSION = "1.47.1"; 25 | const PACKAG_ENAME = "com.pikcloud.pikpak"; 26 | const SDK_VERSION = "2.0.4.204000"; 27 | const APP_NAME = "com.pikcloud.pikpak"; 28 | function captchaInit() { 29 | return new Promise(resolve => { 30 | let meta = {}; 31 | if (/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(info.userName)) { 32 | meta.email = info.userName; 33 | } else if (/\d{11,18}/.test(info.userName)) { 34 | meta.phone_number = info.userName; 35 | } else { 36 | meta.username = info.userName; 37 | } 38 | let params = { 39 | "client_id": CLIENT_ID, 40 | "action": "POST:https://user.mypikpak.com/v1/auth/signin", 41 | "device_id": device_id, 42 | "meta": meta 43 | } 44 | GM_xmlhttpRequest({ 45 | method: 'POST', 46 | url: 'https://user.mypikpak.com/v1/shield/captcha/init', 47 | data: JSON.stringify(params), 48 | onload: (res) => { 49 | if(res.status === 200) { 50 | let data = JSON.parse(res.responseText); 51 | resolve(data); 52 | } else { 53 | info.loginInfo = null; 54 | GM_setValue("pikpakUserInfo", info); 55 | const msg = JSON.parse(res.responseText).error_description; 56 | alert(msg); 57 | } 58 | }, 59 | onerror: (e) => { 60 | GM_notification("Error: " + (e.statusText || e.error)); 61 | }, 62 | ontimeout: (e) => { 63 | GM_notification("Error: " + (e.statusText || e.error)); 64 | } 65 | }); 66 | }); 67 | } 68 | function buildCustomUserAgent() { 69 | let signature_base = `${device_id}${PACKAG_ENAME}1appkey`; 70 | let sha1_result = CryptoJS.SHA1(signature_base).toString(CryptoJS.enc.Hex); 71 | let md5_result = CryptoJS.MD5(sha1_result).toString(CryptoJS.enc.Hex); 72 | 73 | let device_sign = `div101.${device_id}${md5_result}`; 74 | 75 | let user_agent_parts = [ 76 | `ANDROID-${APP_NAME}/${CLIENT_VERSION}`, 77 | "protocolVersion/200", 78 | "accesstype/", 79 | `clientid/${CLIENT_ID}`, 80 | `clientversion/${CLIENT_VERSION}`, 81 | "action_type/", 82 | "networktype/WIFI", 83 | "sessionid/", 84 | `deviceid/${device_id}`, 85 | "providername/NONE", 86 | `devicesign/${device_sign}`, 87 | "refresh_token/", 88 | `sdkversion/${SDK_VERSION}`, 89 | `datetime/${Date.now()}`, 90 | `usrno/${user_id}`, 91 | `appname/${APP_NAME}`, 92 | "session_origin/", 93 | "grant_type/", 94 | "appid/", 95 | "clientip/", 96 | "devicename/Xiaomi_M2004j7ac", 97 | "osversion/13", 98 | "platformversion/10", 99 | "accessmode/", 100 | "devicemodel/M2004J7AC", 101 | ] 102 | 103 | return user_agent_parts.join(" "); 104 | } 105 | document.addEventListener("click", function(e) { 106 | if (e.target && e.target.getAttribute && e.target.getAttribute("name") === "pikpak" && e.target.parentNode.id === "icons") { 107 | GM_setValue("pikpakUserInfo", ""); 108 | alert("PikPak account has been cleared"); 109 | } 110 | }); 111 | var _unsafeWindow = (typeof unsafeWindow === 'undefined') ? window : unsafeWindow; 112 | if (!_unsafeWindow.eoAddons) _unsafeWindow.eoAddons = {}; 113 | _unsafeWindow.eoAddons.pikpak = { 114 | regex: /mypikpak\.com/, 115 | url: "http://user.mypikpak.com/", 116 | bgColor: "2265ff", 117 | noTxt: true, 118 | linkRegExp: /^magnet:\?xt|^PikPak:\/\/|\.(torrent|mp4|mp3|rar|7z|zip|rmvb|mkv|avi|iso)$/i, 119 | directUrl: function(offUrl) { 120 | if (!info) { 121 | let userName = prompt("userName"); 122 | if (!userName) return; 123 | let userPass = prompt("userPass"); 124 | if (!userPass) return; 125 | info = {userName: userName, userPass: userPass}; 126 | GM_setValue("pikpakUserInfo", info); 127 | } 128 | var postUrl = async () => { 129 | let postData; 130 | if (offUrl.indexOf('PikPak://') === 0) { 131 | const urlData = offUrl.substring(9).split('|') 132 | postData = { 133 | kind: "drive#file", 134 | name: urlData[0], 135 | size: urlData[1], 136 | hash: urlData[2], 137 | upload_type: "UPLOAD_TYPE_RESUMABLE", 138 | objProvider: { 139 | provider: "UPLOAD_TYPE_UNKNOWN" 140 | } 141 | } 142 | } else { 143 | postData = { 144 | kind: "drive#file", 145 | name: "", 146 | upload_type: "UPLOAD_TYPE_URL", 147 | url: { 148 | url: offUrl 149 | }, 150 | params: {"from":"file"}, 151 | folder_type: "DOWNLOAD" 152 | } 153 | } 154 | GM_xmlhttpRequest({ 155 | method: 'POST', 156 | url: 'https://api-drive.mypikpak.com/drive/v1/files', 157 | data: JSON.stringify(postData), 158 | headers: { 159 | "Content-Type": "application/json; charset=utf-8", 160 | authorization: info.loginInfo.token_type + ' ' + info.loginInfo.access_token, 161 | "X-Captcha-Token": info.captchaData.captcha_token 162 | }, 163 | onload: (res) => { 164 | if(res.status === 200) { 165 | GM_notification("Task OK"); 166 | } else if(res.status === 401) { 167 | info.loginInfo=null; 168 | GM_setValue("pikpakUserInfo", info); 169 | const msg = JSON.parse(res.responseText).error_description; 170 | alert(msg); 171 | } else if(res.status === 400) { 172 | const msg = JSON.parse(res.responseText).error_description; 173 | alert(msg); 174 | } else if(res.status === 403) { 175 | const msg = JSON.parse(res.responseText).error_description; 176 | alert(msg); 177 | } 178 | }, 179 | onerror: (e) => { 180 | GM_notification("Error: " + (e.statusText || e.error)); 181 | }, 182 | ontimeout: (e) => { 183 | GM_notification("Error: " + (e.statusText || e.error)); 184 | } 185 | }) 186 | }; 187 | device_id = CryptoJS.MD5(`${info.userName}${info.userPass}`).toString(CryptoJS.enc.Hex); 188 | (async () => { 189 | if (!info.captchaData || info.captchaData.expires < new Date().getTime()) { 190 | let captchaData = await captchaInit(); 191 | info.captchaData = captchaData; 192 | if (!info.captchaData.expires && info.captchaData.expires_in) { 193 | info.captchaData.expires = new Date().getTime() + 1000 * info.captchaData.expires_in; 194 | } 195 | GM_setValue("pikpakUserInfo", info); 196 | } 197 | if (!info.loginInfo || info.loginInfo.expires < new Date().getTime()) { 198 | let data = { 199 | "client_id": CLIENT_ID, 200 | "client_secret": CLIENT_SECRET, 201 | "password": info.userPass, 202 | "username": info.userName, 203 | "captcha_token": info.captchaData.captcha_token, 204 | } 205 | GM_xmlhttpRequest({ 206 | method: 'POST', 207 | url: 'https://user.mypikpak.com/v1/auth/signin', 208 | data: JSON.stringify(data), 209 | headers: { 210 | 'user-agent': 'accessmode/ devicename/Netease_Mumu appname/android-com.pikcloud.pikpak cmd/login appid/ action_type/ clientid/YNxT9w7GMdWvEOKa deviceid/56e000d71f4660700ca974f2305171c5 refresh_token/ grant_type/ networktype/WIFI devicemodel/MuMu accesstype/ sessionid/ osversion/6.0.1 datetime/1636364470779 sdkversion/1.0.1.101600 protocolversion/200 clientversion/ providername/NONE clientip/ session_origin/ devicesign/div101.56e000d71f4660700ca974f2305171c5b94c3d4196a9dd74e49d7710a7af873d platformversion/10 usrno/null' 211 | }, 212 | onload: (res) => { 213 | if (res.status === 200) { 214 | info.loginInfo = JSON.parse(res.responseText); 215 | if (!info.loginInfo.expires && info.loginInfo.expires_in) { 216 | info.loginInfo.expires = new Date().getTime() + 1000 * info.loginInfo.expires_in; 217 | } 218 | GM_setValue("pikpakUserInfo", info); 219 | postUrl(); 220 | } else if (res.status === 401) { 221 | GM_setValue("pikpakUserInfo",""); 222 | const msg = JSON.parse(res.responseText).error_description; 223 | alert(msg); 224 | } else if (res.status === 400) { 225 | GM_setValue("pikpakUserInfo",""); 226 | const msg = JSON.parse(res.responseText).error_description; 227 | alert(msg); 228 | } else if (res.status === 403) { 229 | GM_setValue("pikpakUserInfo",""); 230 | const msg = JSON.parse(res.responseText).error_description; 231 | alert(msg); 232 | } 233 | }, 234 | onerror: (e) => { 235 | GM_notification("Error: " + (e.statusText || e.error)); 236 | }, 237 | ontimeout: (e) => { 238 | GM_notification("Error: " + (e.statusText || e.error)); 239 | } 240 | }) 241 | } else { 242 | postUrl(); 243 | } 244 | })(); 245 | return false; 246 | }, 247 | bgImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAYFBMVEUAAAArbP5MdNFMdNIrbP4sbP1QdctQdcwvbv////8dYf8sbP9smP/09/8qaf/V4f8iZf/u8/+lwP+duv+UtP+PsP9hkP92n/9nlP/K2v/F1v+7z/+Ytv9Wif9Aef91nv9e7pgKAAAACHRSTlMA+puT/PWHhQBB7XEAAACQSURBVBjTTY8JCsQwCEWdrjFm37p37n/LMdAJfSTgf4IoAPQf8fDpgek4N9NxnwQZJx0/w+UMNd/XV6nluqsBQbRp79Xqvd7ICBCuaHuElMJhdXEspMKGko/YA2LYXyKuiGt8Ca3rfwm052nbjILV1IyFBZFZck4xppwXQ8Srk2wQzXzcIBpDB8w0/vM4AfwACl4LKjajMX0AAAAASUVORK5CYII=" 248 | }; 249 | })(); -------------------------------------------------------------------------------- /Highlight Every Code/Highlight Every Code.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Highlight Every Code 3 | // @name:zh-CN 代码片段高亮 4 | // @name:zh-TW 程式碼片斷高亮 5 | // @namespace hoothin 6 | // @version 2.2.3.1 7 | // @description Add a icon to popup a window that allows syntax highlighting and beautify and word count of source code snippets on current page 8 | // @description:zh-CN 选择代码片段后点击图标弹出新窗口显示语法高亮美化与格式化后的代码与字数统计 9 | // @description:zh-TW 選擇程式碼片段後點選圖示彈出新視窗顯示語法高亮美化與格式化後的程式碼與字數統計 10 | // @author Hoothin 11 | // @grant GM_registerMenuCommand 12 | // @grant GM.registerMenuCommand 13 | // @grant GM_setValue 14 | // @grant GM.setValue 15 | // @grant GM_getValue 16 | // @grant GM.getValue 17 | // @grant unsafeWindow 18 | // @compatible chrome 19 | // @compatible firefox 20 | // @license MIT License 21 | // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=rixixi@sina.com&item_name=Greasy+Fork+donation 22 | // @contributionAmount 1 23 | // @include * 24 | // ==/UserScript== 25 | 26 | (function() { 27 | 'use strict'; 28 | var codeIcon=document.createElement("img"); 29 | var codes, selStr, scrollX, scrollY, customInput=false,altKey=true,ctrlKey=true,shiftKey=true,metaKey=true,hiding=false; 30 | var _unsafeWindow=(typeof unsafeWindow=='undefined'? window : unsafeWindow); 31 | codeIcon.className="codeIcon"; 32 | codeIcon.style.opacity=0; 33 | codeIcon.title="Show this code snippet"; 34 | codeIcon.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAYAgMAAACD0OXYAAAACVBMVEX7+/swMDBTU1MLxgsCAAAAJElEQVQI12MIBYEAGLUKBBbAqAUMQICgAoAqoBQ95JaCnASjAAgXMdk3d5HTAAAAAElFTkSuQmCC"; 35 | codeIcon.onmousedown=highlight; 36 | var style = document.createElement('style'); 37 | style.textContent = ` 38 | .codeIcon{ 39 | position:fixed; 40 | z-index:99999; 41 | cursor:pointer; 42 | transition:opacity 0.3s ease-in-out 0s; 43 | opacity:0.3; 44 | border:5px solid rgba(0, 0, 0, 0.2); 45 | border-radius:10px; 46 | max-width:30px; 47 | max-height:30px; 48 | overflow:hidden; 49 | } 50 | .codeIcon:hover{ 51 | opacity:0.9; 52 | } 53 | `; 54 | style.type = 'text/css'; 55 | document.head.appendChild(style); 56 | 57 | document.addEventListener('DOMMouseScroll', function(o) { 58 | hideIcon(); 59 | }); 60 | document.addEventListener('wheel', function(o) { 61 | hideIcon(); 62 | }); 63 | document.addEventListener('mousewheel', function(o) { 64 | hideIcon(); 65 | }); 66 | document.addEventListener('mouseover', function(o) { 67 | if(hiding)return; 68 | var target=o.target,hasCode=false; 69 | while(target && target.nodeName!="BODY"){ 70 | if(target.nodeName=="PRE" || target.nodeName=="CODE"){ 71 | hasCode=true; 72 | break; 73 | } 74 | target=target.parentNode; 75 | } 76 | if(!hasCode)return; 77 | if(target.offsetWidth && target.offsetWidth<110)return; 78 | selStr=target.innerText; 79 | if(!selStr)return; 80 | codes=selStr.replace(/&/g, "&").replace(/\/g,">"); 81 | document.body.appendChild(codeIcon); 82 | let pos=getMousePos(o); 83 | scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 84 | scrollY = document.documentElement.scrollTop || document.body.scrollTop; 85 | let top=target.offsetTop-scrollY; 86 | let left=target.offsetLeft-scrollX; 87 | codeIcon.style.opacity=""; 88 | codeIcon.style.top=top+"px"; 89 | codeIcon.style.left=left+"px"; 90 | }); 91 | document.addEventListener('mousedown', function(o) { 92 | hiding=true; 93 | setTimeout(()=>{hiding=false},1000); 94 | hideIcon(); 95 | }); 96 | document.addEventListener('mouseup', function(o) { 97 | if (o.button === 0 && ((!ctrlKey && !altKey && !metaKey && !shiftKey) || (ctrlKey && o.ctrlKey) || (altKey && o.altKey) || (metaKey && o.metaKey) || (shiftKey && o.shiftKey))) { 98 | //var customInputKey=(o.ctrlKey && o.shiftKey); 99 | setTimeout(function(){ 100 | selStr=document.getSelection().toString(); 101 | codes=selStr.replace(/&/g, "&").replace(/\/g,">"); 102 | if(!codes){ 103 | return; 104 | } 105 | document.body.appendChild(codeIcon); 106 | let pos=getMousePos(o); 107 | let clientH=(document.documentElement && document.documentElement.clientHeight) || 0; 108 | let clientW=(document.documentElement && document.documentElement.clientWidth) || 0; 109 | let top=pos.y>clientH-50?(pos.y-30):(pos.y+20); 110 | let left=pos.x>clientW-50?(pos.x-30):(pos.x+20); 111 | codeIcon.style.opacity=""; 112 | codeIcon.style.top=top+"px"; 113 | codeIcon.style.left=left+"px"; 114 | },1); 115 | } 116 | },false); 117 | 118 | function highlight(){ 119 | if(customInput){ 120 | selStr=prompt("Input code here",""); 121 | if(!selStr)return; 122 | codes=selStr.replace(/&/g, "&").replace(/\/g,">"); 123 | } 124 | let html='Code Snippet'+ 125 | ''+ 126 | ''+ 135 | ''+ 136 | ''+ 137 | ''+ 138 | ''+ 139 | 'Code formatting: Javaspcript '+ 140 | 'Html '+ 141 | 'Css '+ 142 | 'Raw ('+selStr.replace(/\s/g,"").length+' words)'+ 143 | '
    ' + codes + "
    "; 144 | 145 | let c = _unsafeWindow.open("", "_blank", "width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=0"); 146 | c.document.write(html); 147 | c.document.close(); 148 | } 149 | function hideIcon(){ 150 | codeIcon.style.opacity=0; 151 | customInput=false; 152 | if(codeIcon.parentNode)codeIcon.parentNode.removeChild(codeIcon); 153 | } 154 | function getMousePos(event) { 155 | var e = event || window.event; 156 | scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 157 | scrollY = document.documentElement.scrollTop || document.body.scrollTop; 158 | var x = (e.pageX || e.clientX) - scrollX; 159 | var y = (e.pageY || e.clientY) - scrollY; 160 | return { 'x': x, 'y': y }; 161 | } 162 | 163 | var _GM_registerMenuCommand; 164 | if(typeof GM_registerMenuCommand!='undefined'){ 165 | _GM_registerMenuCommand=GM_registerMenuCommand; 166 | }else if(typeof GM!='undefined' && typeof GM.registerMenuCommand!='undefined'){ 167 | _GM_registerMenuCommand=GM.registerMenuCommand; 168 | } 169 | if(typeof _GM_registerMenuCommand=='undefined')_GM_registerMenuCommand=(s,f)=>{}; 170 | var storage={ 171 | supportGM: typeof GM_getValue=='function' && typeof GM_getValue('a','b')!='undefined', 172 | supportGMPromise: typeof GM!='undefined' && typeof GM.getValue=='function' && typeof GM.getValue('a','b')!='undefined', 173 | mxAppStorage:(function(){ 174 | try{ 175 | return window.external.mxGetRuntime().storage; 176 | }catch(e){ 177 | }; 178 | })(), 179 | operaUJSStorage:(function(){ 180 | try{ 181 | return window.opera.scriptStorage; 182 | }catch(e){ 183 | }; 184 | })(), 185 | setItem:function(key,value){ 186 | if(this.operaUJSStorage){ 187 | this.operaUJSStorage.setItem(key,value); 188 | }else if(this.mxAppStorage){ 189 | this.mxAppStorage.setConfig(key,value); 190 | }else if(this.supportGM){ 191 | GM_setValue(key,value); 192 | }else if(this.supportGMPromise){ 193 | GM.setValue(key,value); 194 | }else if(window.localStorage){ 195 | window.localStorage.setItem(key,value); 196 | }; 197 | }, 198 | getItem:function(key,cb){ 199 | var value; 200 | if(this.operaUJSStorage){ 201 | value=this.operaUJSStorage.getItem(key); 202 | }else if(this.mxAppStorage){ 203 | value=this.mxAppStorage.getConfig(key); 204 | }else if(this.supportGM){ 205 | value=GM_getValue(key); 206 | }else if(this.supportGMPromise){ 207 | value=GM.getValue(key).then(v=>{cb(v)}); 208 | return; 209 | }else if(window.localStorage){ 210 | value=window.localStorage.getItem(key); 211 | }; 212 | cb(value); 213 | }, 214 | }; 215 | storage.getItem("keyConfig",v=>{ 216 | if(v){ 217 | var keys=v.split(""); 218 | altKey=keys[0]!="0"; 219 | ctrlKey=keys[1]!="0"; 220 | shiftKey=keys[2]!="0"; 221 | metaKey=keys[3]!="0"; 222 | } 223 | if(/greasyfork\.org\/.*\/scripts\/24150[^\/]*$/.test(location.href)){ 224 | var saveConfig=()=>{ 225 | var conStr=""; 226 | conStr+=altKey?"1":"0"; 227 | conStr+=ctrlKey?"1":"0"; 228 | conStr+=shiftKey?"1":"0"; 229 | conStr+=metaKey?"1":"0"; 230 | storage.setItem("keyConfig",conStr); 231 | }; 232 | var keyEles=document.querySelectorAll("h1>em>code"); 233 | keyEles[0].style.userSelect="none"; 234 | keyEles[1].style.userSelect="none"; 235 | keyEles[2].style.userSelect="none"; 236 | keyEles[3].style.userSelect="none"; 237 | keyEles[0].style.opacity=altKey?"":"0.3"; 238 | keyEles[1].style.opacity=ctrlKey?"":"0.3"; 239 | keyEles[2].style.opacity=shiftKey?"":"0.3"; 240 | keyEles[3].style.opacity=metaKey?"":"0.3"; 241 | 242 | keyEles[0].onclick=e=>{ 243 | altKey=!altKey; 244 | keyEles[0].style.opacity=altKey?"":"0.3"; 245 | saveConfig(); 246 | }; 247 | keyEles[1].onclick=e=>{ 248 | ctrlKey=!ctrlKey; 249 | keyEles[1].style.opacity=ctrlKey?"":"0.3"; 250 | saveConfig(); 251 | }; 252 | keyEles[2].onclick=e=>{ 253 | shiftKey=!shiftKey; 254 | keyEles[2].style.opacity=shiftKey?"":"0.3"; 255 | saveConfig(); 256 | }; 257 | keyEles[3].onclick=e=>{ 258 | metaKey=!metaKey; 259 | keyEles[3].style.opacity=metaKey?"":"0.3"; 260 | saveConfig(); 261 | }; 262 | } 263 | }); 264 | 265 | _GM_registerMenuCommand("Custom input to highlight", ()=>{ 266 | selStr=document.getSelection().toString(); 267 | codes=selStr.replace(/&/g, "&").replace(/\/g,">"); 268 | if(!codes){ 269 | customInput=true; 270 | } 271 | highlight(); 272 | }); 273 | })(); -------------------------------------------------------------------------------- /Mouse Gestures/Mouse Gestures.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Greasemonkey Mouse Gestures 3 | // @name:zh-CN 油猴鼠标手势 4 | // @name:zh-TW 油猴滑鼠手勢 5 | // @namespace hoothin 6 | // @version 0.70 7 | // @description Just a Mouse Gestures script 8 | // @description:zh-CN 就是个鼠标手势脚本 9 | // @description:zh-TW 就是個滑鼠手勢脚本 10 | // @author hoothin 11 | // @include * 12 | // @grant GM_openInTab 13 | // @grant GM_setValue 14 | // @grant GM_getValue 15 | // @grant GM_registerMenuCommand 16 | // @grant unsafeWindow 17 | // @grant GM_info 18 | // @license MIT License 19 | // @compatible chrome 20 | // @compatible firefox 21 | // ==/UserScript== 22 | 23 | var lastX,lastY,lastSign,afterGestures,gesturesWords,gesturesContent,gestures,signs; 24 | const defaultFun={ 25 | close:()=>{unsafeWindow.opener=null;unsafeWindow.open('', '_self', '');unsafeWindow.close();}, 26 | openNew:()=>{GM_openInTab('about:newtab', false)}, 27 | scrollToTop:()=>{unsafeWindow.scrollTo(0, 0)}, 28 | scrollToBottom:()=>{unsafeWindow.scrollTo(0, 1073741824)}, 29 | back:()=>{unsafeWindow.history.back()}, 30 | forward:()=>{unsafeWindow.history.forward()}, 31 | reload:()=>{unsafeWindow.location.reload()} 32 | }; 33 | function initEventListener(start,move,end,tracer,clientX,clientY,startBool){ 34 | var isMouse=start=="mousedown"; 35 | var moveFun=function(e){ 36 | tracer(clientX(e),clientY(e),isMouse); 37 | gesturesWords.innerHTML=signs; 38 | var gesturesWidth=signs.length*51+40; 39 | gesturesContent.style.width=gesturesWidth+"px"; 40 | gesturesContent.style.marginLeft=-gesturesWidth/2+"px"; 41 | }; 42 | document.addEventListener(start, function(e) { 43 | if(!startBool || startBool(e)){ 44 | lastX=clientX(e); 45 | lastY=clientY(e); 46 | lastSign=signs=""; 47 | document.addEventListener(move, moveFun, false); 48 | } 49 | }, false); 50 | var endFun=function(e) { 51 | document.removeEventListener(move, moveFun, false); 52 | setTimeout(function(){if(gesturesContent.parentNode)gesturesContent.parentNode.removeChild(gesturesContent);},500); 53 | if(signs){ 54 | if(afterGestures)afterGestures(); 55 | for(var g of gestures){ 56 | var gSign=g.gesture; 57 | if(signs==gSign){ 58 | if(!isMouse)document.body.appendChild(gesturesContent); 59 | var fun=defaultFun[g.fun]; 60 | if(fun===undefined || !fun){ 61 | eval(g.fun); 62 | }else { 63 | fun(); 64 | } 65 | e.stopPropagation(); 66 | e.preventDefault(); 67 | e.returnValue=false; 68 | e.cancelBubble=true; 69 | return false; 70 | } 71 | } 72 | signs=""; 73 | } 74 | }; 75 | document.addEventListener(end, endFun, false); 76 | document.addEventListener("mouseup", endFun, false); 77 | } 78 | (function() { 79 | 'use strict'; 80 | var i18n; 81 | var lang = navigator.appName=="Netscape"?navigator.language:navigator.userLanguage; 82 | const minLength=256,tg=0.5; 83 | switch (lang){ 84 | case "zh-CN": 85 | i18n={ 86 | close:"关闭页面", 87 | openNew:"新建标签页", 88 | scrollToTop:"滚动至最上", 89 | scrollToBottom:"滚动至最下", 90 | back:"后退", 91 | forward:"前进", 92 | reload:"刷新", 93 | addListener:"点击监听鼠标手势", 94 | listening:"正在监听鼠标手势", 95 | bind:"绑定功能", 96 | custom:"自定义代码", 97 | ok:"确定", 98 | del:"删除", 99 | saved:"已设定的手势", 100 | alert1:"请先监听手势", 101 | alert2:"还没有绑定功能", 102 | alert3:"请输入自定义代码", 103 | configure:"鼠标手势设置", 104 | update:"鼠标手势脚本已更新,是否覆盖脚本设置?" 105 | }; 106 | break; 107 | default: 108 | i18n={ 109 | close:"Close tab", 110 | openNew:"Open new tab", 111 | scrollToTop:"Scroll to top", 112 | scrollToBottom:"Scroll to bottom", 113 | back:"Back", 114 | forward:"Forward", 115 | reload:"Reload", 116 | addListener:"Click to add gesture listener", 117 | listening:"Listening", 118 | bind:"Bind function", 119 | custom:"Custom code", 120 | ok:"Ok", 121 | del:"Delete", 122 | saved:"Saved gestures", 123 | alert1:"Please add gesture first", 124 | alert2:"Nothing bind", 125 | alert3:"Input custom code please", 126 | configure:"Mouse Gestures - Configure", 127 | update:"Greasemonkey Mouse Gestures has updated, recover config?" 128 | }; 129 | break; 130 | } 131 | gestures=GM_getValue("gestures"); 132 | if(GM_info.script.version != GM_getValue("gmMouseGestureVersion")){ 133 | if(!gestures || window.confirm(i18n.update)) 134 | gestures=[{gesture:"↓→",fun:"close"}, 135 | {gesture:"→↑",fun:"openNew"}, 136 | {gesture:"←↑",fun:"scrollToTop"}, 137 | {gesture:"←↓",fun:"scrollToBottom"}, 138 | {gesture:"→↑←",fun:"back"}, 139 | {gesture:"←↑→",fun:"forward"}, 140 | {gesture:"↑↓",fun:"reload"}, 141 | {gesture:"↓↑↓",fun:"var t=((unsafeWindow.getSelection&&unsafeWindow.getSelection())||(document.getSelection&&document.getSelection())||(document.selection&&document.selection.createRange&&document.selection.createRange().text));var e=(document.charset||document.characterSet);if(t!=''){GM_openInTab('http://translate.google.cn/?text='+t+'&hl=zh-CN&langpair=auto|zh-CN&tbb=1&ie='+e,false);}else{GM_openInTab('http://translate.google.cn/translate?u='+encodeURIComponent(location.href)+'&hl=zh-CN&langpair=auto|zh-CN&tbb=1&ie='+e,false);}"}, 142 | {gesture:"↓↑↓←",fun:'var d=document,b=d.body;with(b.onselectstart=b.oncopy=b.onpaste=b.onkeydown=b.oncontextmenu=b.onmousemove=b.ondragstart=d.oncopy=d.onpaste=null,d.onselectstart=d.oncontextmenu=d.onmousedown=d.onkeydown=function(){return!0},d.wrappedJSObject||d)onmouseup=null,onmousedown=null,oncontextmenu=null;for(var a=d.getElementsByTagName("*"),i=a.length-1;i>=0;i--){var o=a[i];with(o.wrappedJSObject||o)onmouseup=null,onmousedown=null}var h=d.getElementsByTagName("head")[0];if(h){var s=d.createElement("style");s.innerHTML="html,*{user-select:text!important;-moz-user-select:text!important;-webkit-user-select:text!important;-webkit-user-drag:text!important;-khtml-user-select:text!important;-khtml-user-drag:text!important;pointer-events:auto!important;}",h.appendChild(s)}unsafeWindow.Event.prototype.preventDefault=function(){};'}, 143 | {gesture:"↓↑↓↑",fun:"var d = document, e = d.getElementById('wappalyzer-container') ; if ( e !== null ) { d.body.removeChild(e); } var u = 'https://wappalyzer.com/', t = new Date().getTime(), c = d.createElement('div'), p = d.createElement('div'), l = d.createElement('link'), s = d.createElement('script') ; c.setAttribute('id', 'wappalyzer-container'); l.setAttribute('rel', 'stylesheet'); l.setAttribute('href', u + 'css/bookmarklet.css'); d.head.appendChild(l); p.setAttribute('id', 'wappalyzer-pending'); p.setAttribute('style', 'background-image: url(' + u + 'images/spinner.gif) !important'); c.appendChild(p); s.setAttribute('src', u + 'bookmarklet/wappalyzer.js'); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'bookmarklet/apps.js'); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'bookmarklet/driver.js'); c.appendChild(s); }; c.appendChild(s); }; c.appendChild(s); d.body.appendChild(c);"} 144 | ]; 145 | GM_setValue("gestures",gestures); 146 | GM_setValue("gmMouseGestureVersion",GM_info.script.version); 147 | } 148 | function tracer(curX,curY,showSign) { 149 | let distanceX=curX-lastX,distanceY=curY-lastY; 150 | let distance=distanceX*distanceX+distanceY*distanceY; 151 | if (distance>minLength) { 152 | lastX=curX; 153 | lastY=curY; 154 | let direction=""; 155 | let slope=Math.abs(distanceY/distanceX); 156 | if(slope>tg){ 157 | if(distanceY>0) { 158 | direction="↓"; 159 | }else{ 160 | direction="↑"; 161 | } 162 | }else if(slope<=1/tg) { 163 | if(distanceX>0) { 164 | direction="→"; 165 | }else{ 166 | direction="←"; 167 | } 168 | } 169 | if(lastSign!=direction) { 170 | signs+=direction; 171 | lastSign=direction; 172 | if(showSign)document.body.appendChild(gesturesContent); 173 | } 174 | } 175 | } 176 | gesturesContent=document.createElement("div"); 177 | gesturesContent.id="gesturesContent"; 178 | gesturesContent.style.cssText="width:300px;height:70px;position:fixed;left:50%;top:50%;margin-top:-25px;margin-left:-150px;z-index:999999999;background-color:#000;border:1px solid;border-radius:10px;opacity:0.65;filter:alpha(opacity=65);box-shadow:5px 5px 20px 0px #000;"; 179 | gesturesContent.innerHTML='
    '; 180 | gesturesWords=gesturesContent.querySelector("#gesturesWords"); 181 | initEventListener("touchstart","touchmove","touchend",tracer,e=>{return e.changedTouches[0].clientX},e=>{return e.changedTouches[0].clientY}); 182 | initEventListener("mousedown","mousemove","contextmenu",tracer,e=>{return e.clientX},e=>{return e.clientY},e=>{return e.which === 3}); 183 | if(location.href=="https://github.com/hoothin/UserScripts/tree/master/Mouse%20Gestures"){ 184 | var entryContent=document.querySelector("article.entry-content"),mobile=false; 185 | if(!entryContent){ 186 | mobile=true; 187 | entryContent=document.querySelector(".files-list"); 188 | } 189 | var configBody=document.createElement("div"); 190 | configBody.id="configBody"; 191 | configBody.style.cssText="opacity:0.65;filter:alpha(opacity=65);box-shadow:5px 5px 20px 0px #000;height:160px"; 192 | configBody.innerHTML='
    '; 193 | var configContent=configBody.querySelector("#configContent"); 194 | var newOrEdit=document.createElement("div"); 195 | configContent.appendChild(newOrEdit); 196 | var newOrEditSign=document.createElement("div"); 197 | newOrEditSign.innerHTML=""; 198 | newOrEditSign.style.float="left"; 199 | newOrEdit.appendChild(newOrEditSign); 200 | var newOrEditBtn=document.createElement("input"); 201 | newOrEditBtn.type="button"; 202 | newOrEditBtn.value=i18n.addListener; 203 | newOrEdit.appendChild(newOrEditBtn); 204 | var functionArea=document.createElement("p"); 205 | newOrEdit.appendChild(functionArea); 206 | var functionSelect=document.createElement("select"); 207 | functionSelect.innerHTML=""; 208 | for(var key in defaultFun){ 209 | var optionStr=""; 210 | functionSelect.innerHTML+=optionStr; 211 | } 212 | functionArea.appendChild(functionSelect); 213 | var newOrEditEval=document.createElement("input"); 214 | newOrEditEval.style.width=(mobile?"230":"750")+"px"; 215 | newOrEditEval.style.display="none"; 216 | functionArea.appendChild(newOrEditEval); 217 | var newOrEditOkBtn=document.createElement("input"); 218 | newOrEditOkBtn.type="button"; 219 | newOrEditOkBtn.value=i18n.ok; 220 | newOrEdit.appendChild(newOrEditOkBtn); 221 | var gesturesHas=document.createElement("p"); 222 | newOrEdit.appendChild(gesturesHas); 223 | var gesturesSelect=document.createElement("select"); 224 | var refreshGestures=function(){ 225 | gesturesSelect.innerHTML=""; 226 | gestures.forEach(function(item){ 227 | var optionStr=""; 228 | gesturesSelect.innerHTML+=optionStr; 229 | }); 230 | }; 231 | refreshGestures(); 232 | gesturesHas.appendChild(gesturesSelect); 233 | var newOrEditDelBtn=document.createElement("input"); 234 | newOrEditDelBtn.type="button"; 235 | newOrEditDelBtn.value=i18n.del; 236 | gesturesHas.appendChild(newOrEditDelBtn); 237 | entryContent.insertBefore(configBody,entryContent.firstChild); 238 | functionSelect.onchange=function(){ 239 | if(functionSelect.options.selectedIndex===0)return; 240 | var value=functionSelect.options[functionSelect.options.selectedIndex].value; 241 | newOrEditEval.style.display=(value=="custom"?"initial":"none"); 242 | }; 243 | gesturesSelect.onchange=function(){ 244 | if(gesturesSelect.options.selectedIndex===0)return; 245 | var value=gesturesSelect.options[gesturesSelect.options.selectedIndex].value; 246 | newOrEditSign.innerHTML=value; 247 | gestures.every(function(item){ 248 | if(item.gesture==value){ 249 | functionSelect.options[1].selected = true; 250 | for (var i=2;i