Script Finder+

Script Finder allows you to find userscripts from greasyfork on any website.

As of 2024-07-23. See the latest version.

  1. // ==UserScript==
  2. // @name Script Finder+
  3. // @name:zh-CN Script Finder 油猴脚本查找
  4. // @namespace https://greatest.deepsurf.us/zh-CN/users/1169082
  5. // @version 0.1.6.15
  6. // @description Script Finder allows you to find userscripts from greasyfork on any website.
  7. // @description:zh-CN Script Finder 在任何网站上找到适用于该网站的greasyfork油猴脚本
  8. // @author shiquda & 人民的勤务员 <toniaiwanowskiskr47@gmail.com>
  9. // @namespace https://github.com/shiquda/shiquda_UserScript
  10. // @supportURL https://github.com/shiquda/shiquda_UserScript/issues
  11. // @match *://*/*
  12. // @connect greatest.deepsurf.us
  13. // @icon data:image/jpeg;base64,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
  14. // @grant GM_xmlhttpRequest
  15. // @grant GM_addStyle
  16. // @license AGPL-3.0
  17.  
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. const domainParts = window.location.hostname.split('.').slice(-2)
  22. const domain = domainParts.join('.')
  23. const errorMessage = "Failed to retrieve script information or there are no available scripts for this domain."
  24. let neverLoadedScripts = true
  25. let collapsed = true
  26. let loadedPages = 0
  27.  
  28. function getScriptsInfo(domain, page = 1) {
  29. var url = `https://greatest.deepsurf.us/scripts/by-site/${domain}?filter_locale=0&sort=updated&page=${page}`
  30. GM_xmlhttpRequest({
  31. method: "GET",
  32. url: url,
  33. onload: (response) => {
  34. // 解析结果
  35. const parser = new DOMParser()
  36. const doc = parser.parseFromString(response.responseText, "text/html")
  37. const scripts = doc.querySelector("#browse-script-list")?.querySelectorAll('[data-script-id]')
  38. let scriptsInfo = []
  39.  
  40. if (!scripts) {
  41. scriptsInfo = errorMessage
  42. } else {
  43. for (var i = 0; i < scripts.length; i++) {
  44. scriptsInfo.push(parseScriptInfo(scripts[i]))
  45. }
  46. }
  47.  
  48. // 处理对象
  49. const loadMoreButton = document.querySelector('.load-more')
  50. console.log(doc.querySelector('.next_page'))
  51. if (doc.querySelector('.next_page') == null || doc.querySelector('.next_page')?.getAttribute('aria-disabled') === 'true') {
  52. loadedPages = 'max'
  53. loadMoreButton.disabled = true
  54. loadMoreButton.textContent = 'All scripts loaded'
  55. } else {
  56. loadMoreButton.disabled = false
  57. loadMoreButton.textContent = 'Load more'
  58. }
  59. // console.log(scriptsInfo);
  60. document.querySelector('.wait-loading').style.display = 'none'
  61. loadMoreButton.style.display = 'block'
  62. appendScriptsInfo(scriptsInfo)
  63. updateMatches()
  64.  
  65. typeof (loadedPages) === 'number' ? loadedPages += 1 : loadedPages = loadedPages
  66. // console.log(loadedPages)
  67. },
  68. onerror: () => {
  69. console.log("Some error occurred!")
  70. if (loadedPages === 0) {
  71. appendScriptsInfo(scriptsInfo)
  72. }
  73. const scriptsInfo = errorMessage
  74. document.querySelector('.wait-loading').style.display = 'none'
  75. }
  76. })
  77. }
  78.  
  79. // 解析脚本信息
  80. function parseScriptInfo(script) {
  81. return {
  82. id: script.getAttribute('data-script-id'),
  83. name: script.getAttribute('data-script-name'),
  84. author: script.querySelector("dd.script-list-author").textContent,
  85. description: script.querySelector(".script-description").textContent,
  86. version: script.getAttribute('data-script-version'),
  87. url: 'https://greatest.deepsurf.us/scripts/' + script.getAttribute('data-script-id'),
  88. createDate: script.getAttribute('data-script-created-date'),
  89. updateDate: script.getAttribute('data-script-updated-date'),
  90. installs: script.getAttribute('data-script-total-installs'),
  91. dailyInstalls: script.getAttribute('data-script-daily-installs'),
  92. ratingScore: script.getAttribute('data-script-rating-score')
  93. }
  94. }
  95.  
  96. // 插入脚本
  97. function appendScriptsInfo(scriptsInfo) {
  98. const infoList = document.querySelector('.info-list')
  99. if (scriptsInfo === errorMessage) {
  100. // infoList.innerHTML = errorMessage;
  101. const loadMoreButton = document.querySelector('.load-more')
  102. loadMoreButton.disabled = true
  103. loadMoreButton.textContent = 'All scripts loaded'
  104. loadMoreButton.innerHTML = errorMessage
  105. } else {
  106. for (var i = 0; i < scriptsInfo.length; i++) {
  107. var script = scriptsInfo[i]
  108. var listItem = document.createElement('li')
  109. listItem.className = 'info-item'
  110.  
  111. var scriptContainer = document.createElement('div')
  112. scriptContainer.className = 'script-container'
  113.  
  114. var nameElement = document.createElement('a')
  115. nameElement.className = 'mscript-link'
  116. nameElement.innerText = script.name
  117. nameElement.href = script.url
  118. nameElement.target = '_blank'
  119.  
  120. var descriptionElement = document.createElement('p')
  121. descriptionElement.className = 'script-description'
  122. descriptionElement.innerHTML = script.description
  123.  
  124. var detailsContainer = document.createElement('div')
  125. detailsContainer.className = 'details-container'
  126.  
  127. // 创建一键安装按钮
  128. var installButton = document.createElement('a')
  129. installButton.className = 'install-button'
  130. installButton.innerText = `Install ${script.version}`
  131. installButton.href = `https://greatest.deepsurf.us/scripts/${script.id}/code/script.user.js`
  132.  
  133. const details = [
  134. { key: 'Author', value: script.author },
  135. { key: 'Installs', value: script.installs },
  136. { key: 'Daily Installs', value: script.dailyInstalls },
  137. { key: 'Created', value: script.createDate },
  138. { key: 'Updated', value: script.updateDate },
  139. { key: 'Rating', value: script.ratingScore }
  140. ]
  141.  
  142. for (let i = 0; i < details.length; i++) {
  143. const spanElement = document.createElement('span')
  144. spanElement.className = 'script-details'
  145. spanElement.innerText = `${details[i].key}:\n${details[i].value}`
  146. detailsContainer.appendChild(spanElement)
  147. }
  148.  
  149. scriptContainer.appendChild(nameElement)
  150. scriptContainer.appendChild(descriptionElement)
  151. scriptContainer.appendChild(detailsContainer)
  152. scriptContainer.appendChild(installButton)
  153.  
  154. listItem.appendChild(scriptContainer)
  155. listItem.scriptId = script.id
  156. infoList.appendChild(listItem)
  157. }
  158. }
  159. }
  160.  
  161. function setupUI() {
  162. GM_addStyle(`
  163. button.script-button {
  164. position: fixed;
  165. bottom: 20%;
  166. right: -50px;
  167. transform: translateY(50%);
  168. padding: 20px;
  169. font-size: 16px;
  170. border: none;
  171. border-radius: 4px;
  172. background-color: #1e90ff;
  173. color: #ffffff;
  174. cursor: pointer;
  175. transition: right 0.3s;
  176. z-index: 9999999999999999;
  177. }
  178. div.info-container {
  179. display: none;
  180. position: fixed;
  181. top: 50%;
  182. left: 50%;
  183. transform: translate(-50%, -50%);
  184. width: 650px;
  185. padding: 12px;
  186. background-color: #ffffff;
  187. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
  188. border-radius: 4px;
  189. opacity: 0;
  190. transition: opacity 0.3s;
  191. z-index: 9999;
  192. max-height: 80vh;
  193. overflow-y: auto;
  194. }
  195. ul.info-list {
  196. list-style: none;
  197. margin: 0;
  198. padding: 0;
  199. }
  200. li.info-item {
  201. margin-bottom: 15px;
  202. padding: 12px;
  203. padding-bottom: 22px;
  204. display: flex;
  205. flex-direction: column;
  206. border: 1px solid #1e90ff;
  207. border-radius: 5px;
  208. }
  209. .div.script-container {
  210. display: flex;
  211. flex-direction: column;
  212. }
  213. a.mscript-link {
  214. font-size: 18px !important;
  215. font-weight: bold !important;
  216. margin-bottom: 5px !important;
  217. color: #1e90ff !important;
  218. }
  219. p.script-description {
  220. color: black !important;
  221. margin-top: 2px;
  222. margin-bottom: 5px;
  223. font-size: 16px;
  224. }
  225. div.details-container {
  226. font-size: 15px;
  227. font-weight: bold;
  228. display: flex;
  229. justify-content: space-between;
  230. margin-bottom: 15px;
  231. }
  232. span.script-details {
  233. font: !important;
  234. color: black !important;
  235. flex-grow: 1 !important;
  236. text-align: center !important;
  237. border: 1px solid #1e90ff !important;
  238. border-radius: 5px !important;
  239. margin: 4px !important;
  240. }
  241. div.table-header {
  242. color: #1e90ff !important;
  243. font-size: 25px;
  244. font-weight: bold;
  245. }
  246. input.script-search-input {
  247. width: 96% !important;
  248. padding: 10px !important;
  249. font-size: 18px !important;
  250. border: 1px solid #1e90ff !important;
  251. border-radius: 4px !important;
  252. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3) !important;
  253. margin-bottom: 15px !important;
  254. margin-top: 20px !important;
  255. }
  256. a.install-button {
  257. font-size: 20px;
  258. background-color: green;
  259. color: white;
  260. padding: 12px;
  261. }
  262. button.to-greasyfork {
  263. position: absolute;
  264. top: 12px;
  265. right: 12px;
  266. border-radius: 4px;
  267. padding: 8px;
  268. font-size: 16px;
  269. border: none;
  270. background-color: #1e90ff;
  271. color: #ffffff;
  272. cursor: pointer;
  273. }
  274. span.match-count {
  275. background-color: #1e90ff;
  276. font-size: 25px;
  277. font-weight: bold;
  278. color: white;
  279. padding: 6px;
  280. position: absolute;
  281. right: 50%;
  282. border-radius: 12px;
  283. top: 10px;
  284. }
  285. div.wait-loading {
  286. font-size: 20px;
  287. font-weight: bold;
  288. color: #1e90ff;
  289. animation: blink 1s infinite;
  290. }
  291. @keyframes fadeInOut {
  292. 0% {
  293. opacity: 0;
  294. }
  295. 50% {
  296. opacity: 1;
  297. }
  298. 100% {
  299. opacity: 0;
  300. }
  301. }
  302. @keyframes blink {
  303. 0%, 100% {
  304. opacity: 0;
  305. }
  306. 50% {
  307. opacity: 1;
  308. }
  309. }
  310. button.load-more {
  311. border-radius: 4px;
  312. padding: 8px;
  313. font-size: 16px;
  314. border: none;
  315. background-color: #1e90ff;
  316. color: #ffffff;
  317. cursor: pointer;
  318. position: relative;
  319. bottom: 5px;
  320. left: 50%;
  321. transform: translateX(-50%);
  322. }
  323. button.load-more:disabled {
  324. background-color: #cccccc;
  325. cursor: not-allowed;
  326. }
  327.  
  328. /* Mobile styles */
  329. @media (max-width: 600px) {
  330. button.script-button {
  331. right: -30px;
  332. padding: 8px;
  333. font-size: 14px;
  334. }
  335. span.script-details {
  336. font-size: 10px !important;
  337. margin: 2px !important;
  338. padding: 2px !important;
  339. }
  340. span.match-count {
  341. font-size: 20px;
  342. padding: 4px;
  343. }
  344.  
  345. button.to-greasyfork {
  346. padding: 6px;
  347. font-size: 14px;
  348. }
  349.  
  350. a.install-button {
  351. font-size: 12px;
  352. padding: 8px;
  353. }
  354. div.table-header {
  355. font-size: 20px;
  356. }
  357. div.script-container {
  358. padding: 10px;
  359. }
  360. div.info-container {
  361. top: 10%;
  362. left: 5%;
  363. right: 5%;
  364. transform: none;
  365. width: calc(90% - 10px); /* 自适应宽度,保持左右边距 */
  366. max-width: 100%; /* 确保不超出屏幕宽度 */
  367. }
  368. a.script-link {
  369. font-size: 16px !important;
  370. }
  371. p.script-description {
  372. font-size: 14px;
  373. }
  374. {
  375.  
  376. input.script-search-input {
  377. width: 92% !important;
  378. padding: 8px !important;
  379. font-size: 16px !important;
  380. }
  381. span.match-count {
  382. font-size: 20px;
  383. padding: 4px;
  384. }
  385. button.load-more {
  386. font-size: 14px;
  387. padding: 6px;
  388. }
  389. }
  390. `)
  391.  
  392.  
  393.  
  394. // 创建打开列表按钮
  395. var button = document.createElement('button')
  396. button.className = 'script-button'
  397. button.innerText = 'Scripts'
  398.  
  399. // 创建脚本容器
  400. var infoContainer = document.createElement('div')
  401. infoContainer.className = 'info-container'
  402.  
  403. // 创建搜索框
  404. var searchInput = document.createElement('input')
  405. searchInput.type = 'text'
  406. searchInput.placeholder = 'Search scripts...'
  407. searchInput.className = 'script-search-input'
  408.  
  409. // 创建指向greasyfork的链接
  410. var toGreasyfork = document.createElement('button')
  411. toGreasyfork.className = 'to-greasyfork'
  412. toGreasyfork.innerText = 'View on Greasyfork'
  413.  
  414. // 创建计数器
  415. var matchCount = document.createElement('span')
  416. matchCount.className = 'match-count'
  417.  
  418. // 创建表头
  419. var tableHeader = document.createElement('div')
  420. tableHeader.className = 'table-header'
  421. tableHeader.appendChild(document.createTextNode('Script Finder'))
  422. tableHeader.appendChild(matchCount)
  423. tableHeader.appendChild(searchInput)
  424. tableHeader.appendChild(toGreasyfork)
  425.  
  426. // 创建脚本列表
  427. var infoList = document.createElement('ul')
  428. infoList.className = 'info-list'
  429.  
  430. // 创建等待加载
  431. var waitLoading = document.createElement('div')
  432. waitLoading.className = 'wait-loading'
  433. waitLoading.innerText = 'Loading scripts...'
  434.  
  435. // 创建加载更多
  436. var loadMore = document.createElement('button')
  437. loadMore.className = 'load-more'
  438. loadMore.innerText = 'Load more'
  439. loadMore.style.display = 'none'
  440.  
  441. infoList.appendChild(waitLoading)
  442. infoList.appendChild(loadMore)
  443.  
  444. infoContainer.appendChild(tableHeader)
  445. infoContainer.appendChild(infoList)
  446.  
  447. var timeout
  448. button.addEventListener('mouseenter', function () {
  449. clearTimeout(timeout)
  450. button.style.right = '10px'
  451. })
  452.  
  453. button.addEventListener('mouseleave', function () {
  454. timeout = setTimeout(function () {
  455. button.style.right = '-50px'
  456. }, 500)
  457. })
  458.  
  459. button.addEventListener('click', function (event) {
  460. event.stopPropagation()
  461. if (collapsed) {
  462. infoContainer.style.display = "block"
  463. infoContainer.style.opacity = 1
  464. collapsed = false
  465. }
  466. else {
  467. infoContainer.style.display = "none"
  468. infoContainer.style.opacity = 0
  469. collapsed = true
  470. }
  471.  
  472. if (neverLoadedScripts) {
  473. getScriptsInfo(domain, 1)
  474. neverLoadedScripts = false
  475. }
  476.  
  477. })
  478.  
  479. infoContainer.addEventListener('click', function (event) {
  480. event.stopPropagation()
  481. })
  482.  
  483. searchInput.addEventListener('input', () => {
  484. searchScript()
  485. updateMatches()
  486. })
  487.  
  488. toGreasyfork.addEventListener('click', function () {
  489. window.open(`https://greatest.deepsurf.us/scripts/by-site/${domain}?q=${searchInput.value}&filter_locale=0&sort=updated`)
  490. })
  491.  
  492. loadMore.addEventListener('click', () => {
  493. if (loadedPages === 'max') {
  494. return
  495. }
  496. const loadMoreButton = document.querySelector('.load-more')
  497. loadMoreButton.disabled = true
  498. loadMoreButton.textContent = 'Loading...'
  499. document.querySelector('.wait-loading').style.display = 'block'
  500. getScriptsInfo(domain, loadedPages + 1)
  501. })
  502.  
  503. document.body.addEventListener('click', function () {
  504. clearTimeout(timeout)
  505. collapsed = true
  506. button.style.right = '-50px'
  507. infoContainer.style.opacity = 0
  508. infoContainer.style.display = "none"
  509. })
  510.  
  511. document.body.appendChild(button)
  512.  
  513. document.body.appendChild(infoContainer)
  514.  
  515. infoContainer.addEventListener('change', () => {
  516. updateMatches()
  517. })
  518. updateMatches()
  519. }
  520.  
  521. function searchScript() {
  522. const searchWord = document.querySelector('.script-search-input').value.toLowerCase() // 将要匹配的文本转换为小写
  523. const scriptList = document.querySelectorAll('.info-item')
  524. for (let i = 0; i < scriptList.length; i++) {
  525. const scriptText = scriptList[i].innerText.toLowerCase() // 将检索的文本转换为小写
  526. if (scriptText.includes(searchWord)) {
  527. scriptList[i].style.display = 'block'
  528. } else {
  529. scriptList[i].style.display = 'none'
  530. }
  531. }
  532. }
  533.  
  534. function updateMatches() {
  535. const matchCount = document.querySelectorAll('.info-item:not([style*="display: none"])').length
  536. const allCount = document.querySelectorAll('.info-item').length
  537. document.querySelector('.match-count').innerText = matchCount === allCount ? matchCount : `${matchCount}/${allCount}`
  538. }
  539.  
  540. function main() {
  541. if (window.self !== window.top) {
  542. // 在iframe中执行时,直接退出
  543. return
  544. }
  545. setupUI()
  546. }
  547.  
  548. main()
  549.  
  550.  
  551. })()