Script Finder 油猴脚本查找

Script Finder 在任何网站上找到适用于该网站的 油猴脚本。

目前为 2024-09-06 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Script Finder+
  3. // @name:zh-CN Script Finder 油猴脚本查找
  4. // @description:zh-CN Script Finder 在任何网站上找到适用于该网站的 油猴脚本。
  5. // @name:ar Script Finder البحث عن نص قرد الشحوم
  6. // @description:ar Script Finder ابحث في أي موقع ويب ينطبق على هذا الموقع سيناريو القرد الشحوم。
  7. // @name:bg Script Finder Търсене на скрипт на GreasyFork
  8. // @description:bg Script Finder Намерете във всеки уебсайт, който се отнася за този уебсайт GreasyFork Script。
  9. // @name:cs Script Finder Vyhledávání skriptů GreasyFork
  10. // @description:cs Script Finder Vyhledejte na libovolném webu, který se tohoto webu týká GreasyFork Script。
  11. // @name:da Script Finder GreasyFork Script-opslag
  12. // @description:da Script Finder Find på ethvert websted, der gælder for det pågældende websted GreasyFork Script。
  13. // @name:de Script Finder Nachschlagen von GreasyFork-Skripten
  14. // @description:de Script Finder Finden Sie auf jeder Website, die für diese Website gilt GreasyFork-Skript。
  15. // @name:el Script Finder Αναζήτηση σεναρίου GreasyFork
  16. // @description:el Script Finder Βρείτε σε οποιονδήποτε ιστότοπο που ισχύει για αυτόν τον ιστότοπο Σενάριο GreasyFork。
  17. // @name:en Script Finder GreasyFork Script Lookup
  18. // @description:en Script Finder Find on any website that applies to that website GreasyFork Script。
  19. // @name:eo Script Finder GreasyFork Skripto Serĉo
  20. // @description:eo Script Finder Trovu en iu ajn retejo kiu validas por tiu retejo GreasyFork Skripto。
  21. // @name:es Script Finder Búsqueda de guiones de GreasyFork
  22. // @description:es Script Finder Busque en cualquier sitio web que se aplique a ese sitio web. Guión del mono de grasa。
  23. // @name:fi Script Finder GreasyFork Script Lookup
  24. // @description:fi Script Finder Etsi miltä tahansa verkkosivustoa, joka koskee kyseistä verkkosivustoa GreasyFork Script。
  25. // @name:fr Script Finder Recherche de script GreasyFork
  26. // @description:fr Script Finder Rechercher sur n’importe quel site Web qui s’applique à ce site Web Script de GreasyFork。
  27. // @name:he Script Finder בדיקת סקריפט של גריז קוף
  28. // @description:he Script Finder מצא בכל אתר הרלוונטי לאותו אתר סקריפט גריז קוף。
  29. // @name:hr Script Finder Traženje skripte GreasyFork
  30. // @description:hr Script Finder Pronađite na bilo kojoj web stranici koja se odnosi na tu web stranicu GreasyFork Script。
  31. // @name:hu Script Finder GreasyFork Script Lookup
  32. // @description:hu Script Finder Keresse meg az adott webhelyre vonatkozó bármely webhelyet GreasyFork Script。
  33. // @name:id Script Finder Pencarian Skrip GreasyFork
  34. // @description:id Script Finder Temukan di situs web mana pun yang berlaku untuk situs web tersebut Naskah Monyet Gemuk。
  35. // @name:it Script Finder Ricerca script GreasyFork
  36. // @description:it Script Finder Trova su qualsiasi sito Web che si applica a quel sito Web Sceneggiatura della scimmia grassa。
  37. // @name:ja Script Finder GreasyFork スクリプトの検索
  38. // @description:ja Script Finder その Web サイトに該当する Web サイトを検索する グリース モンキー スクリプト。
  39. // @name:ka Script Finder GreasyFork სკრიპტის ძიება
  40. // @description:ka Script Finder იპოვეთ ნებისმიერ ვებსაიტზე, რომელიც ეხება ამ ვებსაიტს GreasyFork Script。
  41. // @name:ko Script Finder 그리스 원숭이 스크립트 조회
  42. // @description:ko Script Finder 해당 웹사이트에 적용되는 웹사이트를 찾으세요. 그리스 원숭이 스크립트。
  43. // @name:nl Script Finder GreasyFork-script opzoeken
  44. // @description:nl Script Finder Zoek op elke website wat op die website van toepassing is GreasyFork-script。
  45. // @name:nb Script Finder GreasyFork Script Lookup
  46. // @description:nb Script Finder Finn på et hvilket som helst nettsted som gjelder for det nettstedet GreasyFork Script。
  47. // @name:pl Script Finder Wyszukiwanie skryptu GreasyFork
  48. // @description:pl Script Finder Znajdź na dowolnej stronie internetowej, która dotyczy tej witryny Smaruj skrypt małpy。
  49. // @name:pt-BR Script Finder Pesquisa de script do GreasyFork
  50. // @description:pt-BR Script Finder Encontre em qualquer site que se aplique a esse site Script do Macaco Graxa。
  51. // @name:ro Script Finder Căutare Script GreasyFork
  52. // @description:ro Script Finder Găsiți pe orice site care se aplică acelui site GreasyFork Script。
  53. // @name:ru Script Finder Поиск сценария GreasyFork
  54. // @description:ru Script Finder Найти на любом веб-сайте, который относится к этому веб-сайту Сценарий GreasyFork。
  55. // @name:sk Script Finder Vyhľadávanie skriptov GreasyFork
  56. // @description:sk Script Finder Nájdite na ľubovoľnej webovej lokalite, ktorá sa týka danej webovej lokality GreasyFork Script。
  57. // @name:sr Script Finder Греасе Монкеи Сцрипт Лоокуп
  58. // @description:sr Script Finder Пронађите на било којој веб локацији која се односи на ту веб локацију Греасе Монкеи Сцрипт。
  59. // @name:sv Script Finder GreasyFork Script Lookup
  60. // @description:sv Script Finder Hitta på vilken webbplats som helst som gäller den webbplatsen GreasyFork Script。
  61. // @name:th Script Finder ค้นหาสคริปต์ GreasyFork
  62. // @description:th Script Finder ค้นหาบนเว็บไซต์ใด ๆ ที่ใช้กับเว็บไซต์นั้น สคริปต์ลิงจาระบี。
  63. // @name:tr Script Finder GreasyFork Komut Dosyası Arama
  64. // @description:tr Script Finder Söz konusu web sitesi için geçerli olan herhangi bir web sitesinde bulun GreasyFork Komut Dosyası。
  65. // @name:ug Script Finder مايمۇن قوليازمىسىنى ئىزدەش
  66. // @description:ug Script Finder شۇ تور بېكەتكە ماس كېلىدىغان ھەرقانداق تور بەتنى ئىزدەڭ مايمۇن قوليازمىسى。
  67. // @name:uk Script Finder Пошук сценарію GreasyFork
  68. // @description:uk Script Finder Знайдіть на будь-якому веб-сайті, який стосується цього веб-сайту Сценарій GreasyFork。
  69. // @name:vi Script Finder Tra cứu tập lệnh GreasyFork
  70. // @description:vi Script Finder Tìm trên bất kỳ trang web nào áp dụng cho trang web đó Kịch bản khỉ mỡ。
  71. // @name:zh-TW Script Finder 油猴腳本查找
  72. // @description:zh-TW Script Finder 在任何網站上找到適用於該網站的 油猴腳本。
  73. // @name:zh-HK Script Finder 油猴腳本查找
  74. // @description:zh-HK Script Finder 在任何網站上找到適用於該網站的 油猴腳本。
  75. // @name:fr-CA Script Finder Recherche de script GreasyFork
  76. // @description:fr-CA Script Finder Rechercher sur n’importe quel site Web qui s’applique à ce site Web Script de GreasyFork。
  77. // @description Script Finder allows you to find userscripts from greasyfork on any website.
  78.  
  79. // @namespace https://greasyfork.org/zh-CN/users/1169082
  80. // @version 0.1.6.71
  81. // @author shiquda & 人民的勤务员 <toniaiwanowskiskr47@gmail.com>
  82. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  83. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  84. // @match *://*/*
  85. // @connect greasyfork.org
  86. // @icon https://github.com/ChinaGodMan/UserScripts/raw/main/docs/icon/Scripts%20Icons/Finder.jpg
  87. // @grant GM_xmlhttpRequest
  88. // @grant GM_addStyle
  89. // @license MIT
  90.  
  91. // ==/UserScript==
  92. const translate = (function () {
  93. const userLang = (navigator.languages && navigator.languages[0]) || navigator.language || 'en'
  94. const strings = {
  95. 'en': {
  96. Author: 'Author',
  97. Installs: 'Installs',
  98. DailyInstalls: 'Daily Installs',
  99. Created: 'Created',
  100. Updated: 'Updated',
  101. Rating: 'Rating',
  102. LoadingScripts: 'Loading scripts...',
  103. LoadMore: 'Load more',
  104. AllScriptsLoaded: 'All scripts loaded',
  105. SearchPlaceholder: 'Search scripts...',
  106. ViewOnGreasyfork: 'View on Greasyfork',
  107. errorMessage: 'Failed to retrieve script information or there are no available scripts for this domain.',
  108. Loading: 'Loading...',
  109. Scripts: 'Scripts'
  110. },
  111. 'zh-CN': {
  112. Author: '作者',
  113. Installs: '安装数量',
  114. DailyInstalls: '每日安装',
  115. Created: '创建日期',
  116. Updated: '更新时间',
  117. Rating: '评分',
  118. LoadingScripts: '正在加载脚本...',
  119. LoadMore: '加载更多',
  120. AllScriptsLoaded: '所有脚本已加载',
  121. SearchPlaceholder: '搜索脚本...',
  122. ViewOnGreasyfork: '在Greasyfork查看',
  123. errorMessage: '无法检索脚本信息或该域没有可用的脚本。',
  124. Loading: '载入中...',
  125. Scripts: '脚本'
  126.  
  127. },
  128. 'zh-TW': {
  129. Author: '作者',
  130. Installs: '安裝數量',
  131. DailyInstalls: '每日安裝',
  132. Created: '創建日期',
  133. Updated: '更新日期',
  134. Rating: '評分',
  135. LoadingScripts: '正在載入腳本...',
  136. LoadMore: '載入更多',
  137. AllScriptsLoaded: '所有腳本已載入',
  138. SearchPlaceholder: '搜尋腳本...',
  139. ViewOnGreasyfork: '在Greasyfork查看',
  140. errorMessage: '無法檢索腳本信息或該域沒有可用的腳本。',
  141. Loading: '載入中...',
  142. Scripts: '腳本'
  143. },
  144. 'ja': {
  145. Author: '著者',
  146. Installs: 'インストール数',
  147. DailyInstalls: '日次インストール数',
  148. Created: '作成日',
  149. Updated: '更新日',
  150. Rating: '評価',
  151. LoadingScripts: 'スクリプトを読み込んでいます...',
  152. LoadMore: 'もっと読む',
  153. AllScriptsLoaded: 'すべてのスクリプトが読み込まれました',
  154. SearchPlaceholder: 'スクリプトを検索...',
  155. ViewOnGreasyfork: 'Greasyforkで見る',
  156. errorMessage: 'スクリプト情報の取得に失敗するか、またはこのドメインには利用可能なスクリプトがありません。',
  157. Loading: '読み込み中...',
  158. Scripts: 'スクリプト'
  159. },
  160. 'vi': {
  161. Author: 'Tác giả',
  162. Installs: 'Số lượt cài đặt',
  163. DailyInstalls: 'Cài đặt hàng ngày',
  164. Created: 'Ngày tạo',
  165. Updated: 'Ngày cập nhật',
  166. Rating: 'Đánh giá',
  167. LoadingScripts: 'Đang tải các tập lệnh...',
  168. LoadMore: 'Tải thêm',
  169. AllScriptsLoaded: 'Đã tải tất cả các tập lệnh',
  170. SearchPlaceholder: 'Tìm kiếm tập lệnh...',
  171. ViewOnGreasyfork: 'Xem trên Greasyfork',
  172. errorMessage: 'Không thể truy xuất thông tin tập lệnh hoặc không có tập lệnh nào có sẵn cho miền này.',
  173. Loading: 'Đang tải...',
  174. Scripts: 'Tập lệnh'
  175. }
  176. }
  177. // 返回翻译函数
  178. return (id, lang = '') => {
  179. const selectedLang = lang || userLang
  180. return (strings[selectedLang] || strings.en)[id] || strings.en[id]
  181. }
  182. }());
  183. (function () {
  184. const domainParts = window.location.hostname.split('.').slice(-2)
  185. const domain = domainParts.join('.')
  186. const errorMessage = translate('errorMessage')
  187. let neverLoadedScripts = true
  188. let collapsed = true
  189. let loadedPages = 0
  190.  
  191. function getScriptsInfo(domain, page = 1) {
  192. var url = `https://greasyfork.org/scripts/by-site/${domain}?filter_locale=0&sort=updated&page=${page}`
  193.  
  194. GM_xmlhttpRequest({
  195. method: "GET",
  196. url: url,
  197. onload: (response) => {
  198. // 解析结果
  199. const parser = new DOMParser()
  200. const doc = parser.parseFromString(response.responseText, "text/html")
  201. const scripts = doc.querySelector("#browse-script-list")?.querySelectorAll('[data-script-id]')
  202. let scriptsInfo = []
  203.  
  204. if (!scripts) {
  205. scriptsInfo = errorMessage
  206. } else {
  207. for (var i = 0; i < scripts.length; i++) {
  208. scriptsInfo.push(parseScriptInfo(scripts[i]))
  209. }
  210. }
  211.  
  212. // 处理对象
  213. const loadMoreButton = document.querySelector('.load-more')
  214. console.log(doc.querySelector('.next_page'))
  215. if (doc.querySelector('.next_page') == null || doc.querySelector('.next_page')?.getAttribute('aria-disabled') === 'true') {
  216. loadedPages = 'max'
  217. loadMoreButton.disabled = true
  218. loadMoreButton.textContent = translate('AllScriptsLoaded')
  219. } else {
  220. loadMoreButton.disabled = false
  221. loadMoreButton.textContent = translate('LoadMore')
  222. }
  223. // console.log(scriptsInfo);
  224. document.querySelector('.wait-loading').style.display = 'none'
  225. loadMoreButton.style.display = 'block'
  226. appendScriptsInfo(scriptsInfo)
  227. updateMatches()
  228.  
  229. typeof (loadedPages) === 'number' ? loadedPages += 1 : loadedPages = loadedPages
  230. // console.log(loadedPages)
  231. },
  232. onerror: () => {
  233. console.log("Some error occurred!")
  234. if (loadedPages === 0) {
  235. appendScriptsInfo(scriptsInfo)
  236. }
  237. const scriptsInfo = errorMessage
  238. document.querySelector('.wait-loading').style.display = 'none'
  239. }
  240. })
  241. }
  242.  
  243. // 解析脚本信息
  244. function parseScriptInfo(script) {
  245. return {
  246. id: script.getAttribute('data-script-id'),
  247. name: script.getAttribute('data-script-name'),
  248. author: script.querySelector("dd.script-list-author").textContent,
  249. description: script.querySelector(".script-description").textContent,
  250. version: script.getAttribute('data-script-version'),
  251. url: 'https://greasyfork.org/scripts/' + script.getAttribute('data-script-id'),
  252. createDate: script.getAttribute('data-script-created-date'),
  253. updateDate: script.getAttribute('data-script-updated-date'),
  254. installs: script.getAttribute('data-script-total-installs'),
  255. dailyInstalls: script.getAttribute('data-script-daily-installs'),
  256. ratingScore: script.getAttribute('data-script-rating-score')
  257. }
  258. }
  259.  
  260. // 插入脚本
  261. function appendScriptsInfo(scriptsInfo) {
  262. const infoList = document.querySelector('.info-list')
  263. if (scriptsInfo === errorMessage) {
  264. // infoList.innerHTML = errorMessage;
  265. const loadMoreButton = document.querySelector('.load-more')
  266. loadMoreButton.disabled = true
  267. loadMoreButton.textContent = translate('AllScriptsLoaded')
  268. loadMoreButton.innerHTML = errorMessage
  269. } else {
  270. for (var i = 0; i < scriptsInfo.length; i++) {
  271. var script = scriptsInfo[i]
  272. var listItem = document.createElement('li')
  273. listItem.className = 'info-item'
  274.  
  275. var scriptContainer = document.createElement('div')
  276. scriptContainer.className = 'script-container'
  277.  
  278. var nameElement = document.createElement('a')
  279. nameElement.className = 'mscript-link'
  280. nameElement.innerText = script.name
  281. nameElement.href = script.url
  282. nameElement.target = '_blank'
  283.  
  284. var descriptionElement = document.createElement('p')
  285. descriptionElement.className = 'script-description'
  286. descriptionElement.innerHTML = script.description
  287.  
  288. var detailsContainer = document.createElement('div')
  289. detailsContainer.className = 'details-container'
  290.  
  291. // 创建一键安装按钮
  292. var installButton = document.createElement('a')
  293. installButton.className = 'install-button'
  294. installButton.innerText = `Install ${script.version}`
  295. installButton.href = `https://greasyfork.org/scripts/${script.id}/code/script.user.js`
  296.  
  297. const details = [
  298. { key: translate('Author'), value: script.author },
  299. { key: translate('Installs'), value: script.installs },
  300. { key: translate('DailyInstalls'), value: script.dailyInstalls },
  301. { key: translate('Created'), value: script.createDate },
  302. { key: translate('Updated'), value: script.updateDate },
  303. { key: translate('Rating'), value: script.ratingScore }
  304. ]
  305.  
  306. for (let i = 0; i < details.length; i++) {
  307. const spanElement = document.createElement('span')
  308. spanElement.className = 'script-details'
  309. spanElement.innerText = `${details[i].key}:\n${details[i].value}`
  310. detailsContainer.appendChild(spanElement)
  311. }
  312.  
  313. scriptContainer.appendChild(nameElement)
  314. scriptContainer.appendChild(descriptionElement)
  315. scriptContainer.appendChild(detailsContainer)
  316. scriptContainer.appendChild(installButton)
  317.  
  318. listItem.appendChild(scriptContainer)
  319. listItem.scriptId = script.id
  320. infoList.appendChild(listItem)
  321. }
  322. }
  323. }
  324.  
  325. function setupUI() {
  326. GM_addStyle(`
  327. scrbutton.script-button {
  328. position: fixed;
  329. bottom: 20%;
  330. right: -50px;
  331. transform: translateY(50%);
  332. padding: 20px;
  333. font-size: 16px;
  334. border: none;
  335. border-radius: 4px;
  336. background-color: #1e90ff;
  337. color: #ffffff;
  338. cursor: pointer;
  339. transition: right 0.3s;
  340. z-index: 9999999999999999;
  341. }
  342. div.info-container {
  343. display: none;
  344. position: fixed;
  345. top: 50%;
  346. left: 50%;
  347. transform: translate(-50%, -50%);
  348. width: 650px;
  349. padding: 12px;
  350. background-color: #ffffff;
  351. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
  352. border-radius: 4px;
  353. opacity: 0;
  354. transition: opacity 0.3s;
  355. z-index: 9999;
  356. max-height: 80vh;
  357. overflow-y: auto;
  358. }
  359. ul.info-list {
  360. list-style: none;
  361. margin: 0;
  362. padding: 0;
  363. }
  364. li.info-item {
  365. margin-bottom: 15px;
  366. padding: 12px;
  367. padding-bottom: 22px;
  368. display: flex;
  369. flex-direction: column;
  370. border: 1px solid #1e90ff;
  371. border-radius: 5px;
  372. }
  373. .div.script-container {
  374. display: flex;
  375. flex-direction: column;
  376. }
  377. a.mscript-link {
  378. font-size: 18px !important;
  379. font-weight: bold !important;
  380. margin-bottom: 5px !important;
  381. color: #1e90ff !important;
  382. }
  383. p.script-description {
  384. color: black !important;
  385. margin-top: 2px;
  386. margin-bottom: 5px;
  387. font-size: 16px;
  388. }
  389. div.details-container {
  390. font-size: 15px;
  391. font-weight: bold;
  392. display: flex;
  393. justify-content: space-between;
  394. margin-bottom: 15px;
  395. }
  396. span.script-details {
  397. font: !important;
  398. color: black !important;
  399. flex-grow: 1 !important;
  400. text-align: center !important;
  401. border: 1px solid #1e90ff !important;
  402. border-radius: 5px !important;
  403. margin: 4px !important;
  404. }
  405. div.table-header {
  406. color: #1e90ff !important;
  407. font-size: 25px;
  408. font-weight: bold;
  409. }
  410. input.script-search-input {
  411. width: 96% !important;
  412. padding: 10px !important;
  413. font-size: 18px !important;
  414. border: 1px solid #1e90ff !important;
  415. border-radius: 4px !important;
  416. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3) !important;
  417. margin-bottom: 15px !important;
  418. margin-top: 20px !important;
  419. }
  420. a.install-button {
  421. font-size: 20px;
  422. background-color: green;
  423. color: white;
  424. padding: 12px;
  425. }
  426. button.to-greasyfork {
  427. position: absolute;
  428. top: 12px;
  429. right: 12px;
  430. border-radius: 4px;
  431. padding: 8px;
  432. font-size: 16px;
  433. border: none;
  434. background-color: #1e90ff;
  435. color: #ffffff;
  436. cursor: pointer;
  437. }
  438. span.match-count {
  439. background-color: #1e90ff;
  440. font-size: 25px;
  441. font-weight: bold;
  442. color: white;
  443. padding: 6px;
  444. position: absolute;
  445. right: 50%;
  446. border-radius: 12px;
  447. top: 10px;
  448. }
  449. div.wait-loading {
  450. font-size: 20px;
  451. font-weight: bold;
  452. color: #1e90ff;
  453. animation: blink 1s infinite;
  454. }
  455. @keyframes fadeInOut {
  456. 0% {
  457. opacity: 0;
  458. }
  459. 50% {
  460. opacity: 1;
  461. }
  462. 100% {
  463. opacity: 0;
  464. }
  465. }
  466. @keyframes blink {
  467. 0%, 100% {
  468. opacity: 0;
  469. }
  470. 50% {
  471. opacity: 1;
  472. }
  473. }
  474. button.load-more {
  475. border-radius: 4px;
  476. padding: 8px;
  477. font-size: 16px;
  478. border: none;
  479. background-color: #1e90ff;
  480. color: #ffffff;
  481. cursor: pointer;
  482. position: relative;
  483. bottom: 5px;
  484. left: 50%;
  485. transform: translateX(-50%);
  486. }
  487. button.load-more:disabled {
  488. background-color: #cccccc;
  489. cursor: not-allowed;
  490. }
  491.  
  492. /* Mobile styles */
  493. @media (max-width: 600px) {
  494. scrbutton.script-button {
  495. right: -30px;
  496. padding: 8px;
  497. font-size: 14px;
  498. }
  499. span.script-details {
  500. font-size: 10px !important;
  501. margin: 2px !important;
  502. padding: 2px !important;
  503. }
  504. span.match-count {
  505. font-size: 20px;
  506. padding: 4px;
  507. }
  508.  
  509. button.to-greasyfork {
  510. padding: 6px;
  511. font-size: 14px;
  512. }
  513.  
  514. a.install-button {
  515. font-size: 12px;
  516. padding: 8px;
  517. }
  518. div.table-header {
  519. font-size: 20px;
  520. }
  521. div.script-container {
  522. padding: 10px;
  523. }
  524. div.info-container {
  525. top: 10%;
  526. left: 5%;
  527. right: 5%;
  528. transform: none;
  529. width: calc(90% - 10px); /* 自适应宽度,保持左右边距 */
  530. max-width: 100%; /* 确保不超出屏幕宽度 */
  531. }
  532. a.script-link {
  533. font-size: 16px !important;
  534. }
  535. p.script-description {
  536. font-size: 14px;
  537. }
  538. {
  539.  
  540. input.script-search-input {
  541. width: 92% !important;
  542. padding: 8px !important;
  543. font-size: 16px !important;
  544. }
  545. span.match-count {
  546. font-size: 20px;
  547. padding: 4px;
  548. }
  549. button.load-more {
  550. font-size: 14px;
  551. padding: 6px;
  552. }
  553. }
  554. `)
  555.  
  556.  
  557. // 创建打开列表按钮
  558. var button = document.createElement('scrbutton')
  559. button.className = 'script-button'
  560. button.innerText = translate('Scripts')
  561. document.addEventListener('fullscreenchange', function () {
  562. if (document.fullscreenElement) {
  563. button.style.display = 'none'
  564. } else {
  565. button.style.display = 'block'
  566. }
  567. })
  568. // 创建脚本容器
  569. var infoContainer = document.createElement('div')
  570. infoContainer.className = 'info-container'
  571.  
  572. // 创建搜索框
  573. var searchInput = document.createElement('input')
  574. searchInput.type = 'text'
  575. searchInput.placeholder = translate('SearchPlaceholder')
  576. searchInput.className = 'script-search-input'
  577.  
  578. // 创建指向greasyfork的链接
  579. var toGreasyfork = document.createElement('button')
  580. toGreasyfork.className = 'to-greasyfork'
  581. toGreasyfork.innerText = translate('ViewOnGreasyfork')
  582.  
  583. // 创建计数器
  584. var matchCount = document.createElement('span')
  585. matchCount.className = 'match-count'
  586.  
  587. // 创建表头
  588. var tableHeader = document.createElement('div')
  589. tableHeader.className = 'table-header'
  590. tableHeader.appendChild(document.createTextNode('Script Finder'))
  591. tableHeader.appendChild(matchCount)
  592. tableHeader.appendChild(searchInput)
  593. tableHeader.appendChild(toGreasyfork)
  594.  
  595. // 创建脚本列表
  596. var infoList = document.createElement('ul')
  597. infoList.className = 'info-list'
  598.  
  599. // 创建等待加载
  600. var waitLoading = document.createElement('div')
  601. waitLoading.className = 'wait-loading'
  602. waitLoading.innerText = translate('LoadingScripts')
  603.  
  604. // 创建加载更多
  605. var loadMore = document.createElement('button')
  606. loadMore.className = 'load-more'
  607. loadMore.innerText = 'Load more'
  608. loadMore.style.display = 'none'
  609.  
  610. infoList.appendChild(waitLoading)
  611. infoList.appendChild(loadMore)
  612.  
  613. infoContainer.appendChild(tableHeader)
  614. infoContainer.appendChild(infoList)
  615.  
  616. var timeout
  617. button.addEventListener('mouseenter', function () {
  618. clearTimeout(timeout)
  619. button.style.right = '10px'
  620. })
  621.  
  622. button.addEventListener('mouseleave', function () {
  623. timeout = setTimeout(function () {
  624. button.style.right = '-50px'
  625. }, 500)
  626. })
  627.  
  628. button.addEventListener('click', function (event) {
  629. event.stopPropagation()
  630. if (collapsed) {
  631. infoContainer.style.display = "block"
  632. infoContainer.style.opacity = 1
  633. collapsed = false
  634. }
  635. else {
  636. infoContainer.style.display = "none"
  637. infoContainer.style.opacity = 0
  638. collapsed = true
  639. }
  640.  
  641. if (neverLoadedScripts) {
  642. getScriptsInfo(domain, 1)
  643. neverLoadedScripts = false
  644. }
  645.  
  646. })
  647.  
  648. infoContainer.addEventListener('click', function (event) {
  649. event.stopPropagation()
  650. })
  651.  
  652. searchInput.addEventListener('input', () => {
  653. searchScript()
  654. updateMatches()
  655. })
  656.  
  657. toGreasyfork.addEventListener('click', function () {
  658. window.open(`https://greasyfork.org/scripts/by-site/${domain}?q=${searchInput.value}&filter_locale=0&sort=updated`)
  659. })
  660.  
  661. loadMore.addEventListener('click', () => {
  662. if (loadedPages === 'max') {
  663. return
  664. }
  665. const loadMoreButton = document.querySelector('.load-more')
  666. loadMoreButton.disabled = true
  667. loadMoreButton.textContent = translate('Loading')
  668. document.querySelector('.wait-loading').style.display = 'block'
  669. getScriptsInfo(domain, loadedPages + 1)
  670. })
  671.  
  672. document.body.addEventListener('click', function () {
  673. clearTimeout(timeout)
  674. collapsed = true
  675. button.style.right = '-50px'
  676. infoContainer.style.opacity = 0
  677. infoContainer.style.display = "none"
  678. })
  679.  
  680. document.body.appendChild(button)
  681.  
  682. document.body.appendChild(infoContainer)
  683.  
  684. infoContainer.addEventListener('change', () => {
  685. updateMatches()
  686. })
  687. updateMatches()
  688. }
  689.  
  690. function searchScript() {
  691. const searchWord = document.querySelector('.script-search-input').value.toLowerCase() // 将要匹配的文本转换为小写
  692. const scriptList = document.querySelectorAll('.info-item')
  693. for (let i = 0; i < scriptList.length; i++) {
  694. const scriptText = scriptList[i].innerText.toLowerCase() // 将检索的文本转换为小写
  695. if (scriptText.includes(searchWord)) {
  696. scriptList[i].style.display = 'block'
  697. } else {
  698. scriptList[i].style.display = 'none'
  699. }
  700. }
  701. }
  702.  
  703. function updateMatches() {
  704. const matchCount = document.querySelectorAll('.info-item:not([style*="display: none"])').length
  705. const allCount = document.querySelectorAll('.info-item').length
  706. document.querySelector('.match-count').innerText = matchCount === allCount ? matchCount : `${matchCount}/${allCount}`
  707. }
  708.  
  709. function main() {
  710. if (window.self !== window.top) {
  711. // 在iframe中执行时,直接退出
  712. return
  713. }
  714. setupUI()
  715. }
  716.  
  717. main()
  718.  
  719.  
  720. })()