GreasyFork Search

To search scripts using Google Search

当前为 2023-09-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork Search
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6.1
  5. // @description To search scripts using Google Search
  6. // @author CY Fung
  7. // @match https://gf.qytechs.cn/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=gf.qytechs.cn
  9. // @require https://fastly.jsdelivr.net/npm/jstat@1.9.6/dist/jstat.min.js
  10. // @grant none
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14.  
  15.  
  16. (() => {
  17.  
  18. function getVN(A) {
  19. // normalized the matrix values such that det(A) will be a finite value close to 1.0
  20. // vn = sqrt( ( column_vector_1 ^2 + column_vector_2 ^2 + ... + column_vector_n ^2 ) / n )
  21. let vn = 0;
  22. const AT = jStat.transpose(A);
  23. let N = AT.length;
  24. for (let i = 0; i < N; i++) {
  25. vn += jStat.dot(AT[i], AT[i]);
  26. }
  27. vn = Math.sqrt(vn / N);
  28. return vn;
  29. }
  30.  
  31. function subtractLambdaFromDiagonal(matrix, lambda) {
  32. // A - lambda I
  33. return matrix.map((row, rowIndex) => row.map((val, colIndex) => rowIndex === colIndex ? val - lambda : val));
  34. }
  35.  
  36.  
  37. function eigenvalueNewton(A, lambda0) {
  38. const N = A.length;
  39. const epsilon = 1e-5; // epsilon is applied on the normalized scale of lambda
  40. const maxTrial = 8;
  41.  
  42. function f(lambda) {
  43. return jStat.det(subtractLambdaFromDiagonal(A, lambda));
  44. }
  45.  
  46. function fPrime(lambda) {
  47. return (f(lambda + epsilon) - f(lambda)) / epsilon;
  48. }
  49.  
  50. let x_k = lambda0;
  51. let positiveSign = 0;
  52. let negativeSign = 0;
  53. for (let i = 0; i < maxTrial; i++) {
  54. const fx = f(x_k);
  55. const fxPrime = fPrime(x_k);
  56. const diff = fx / fxPrime;
  57. if (isNaN(diff)) return x_k; // ignore f/f'
  58. const x_k1 = x_k - diff;
  59. if ((diff > 0 ? diff : -diff) < epsilon) {
  60. return x_k1;
  61. }
  62. x_k = x_k1;
  63. if (fx > 0) positiveSign = 1;
  64. else if (fx < 0) negativeSign = 1;
  65. }
  66. return positiveSign && negativeSign ? x_k : lambda0; // avoid diverging iterations
  67. }
  68.  
  69. function vectorNorm(v) {
  70. // Math.sqrt(v dot v), same as jStat.norm(jStat.transpose(v))
  71. let s = 0;
  72. for (const k of v) s += k[0] * k[0];
  73. return Math.sqrt(s);
  74. }
  75.  
  76. function isUnitVector(v, tol = 0.01) {
  77. // Check if it is likely a unit vector
  78. let s = 0;
  79. for (const k of v) {
  80. s += k[0] * k[0];
  81. if (s > 1 + tol) return false;
  82. }
  83. return s > 1 - tol;
  84. }
  85.  
  86. jStat.jacobiOri = jStat.jacobi;
  87. // https://www.statskingdom.com/pca-calculator.html
  88. jStat.jacobi = function (C) {
  89.  
  90. const vn = getVN(C);
  91. C = jStat.multiply(C, 1 / vn);
  92. let r1 = jStat.jacobiOri(C);
  93. // let r0 = JSON.parse(JSON.stringify(r1))
  94. // r0[1] = r0[1].map(v => vn * v);
  95. let A = C;
  96. let eigenvectors = r1[0];
  97. let eigenvalues = r1[1];
  98. const iterationCount = 4;
  99.  
  100. for (let i = 0; i < eigenvalues.length; i++) {
  101. let q, m;
  102. q = jStat.transpose(eigenvectors[i]);
  103. if (!isUnitVector(q)) break;
  104. eigenvalues[i] = eigenvalueNewton(A, eigenvalues[i]); // refine eigenvalues obtained in jacobiOri
  105.  
  106. // inverse power method (A-lambda I) y_k = b_{k-1}
  107. // b_k = y_k / norm(y_k)
  108. let M = subtractLambdaFromDiagonal(A, eigenvalues[i]);
  109. for (let j = 0; j < iterationCount; j++) {
  110. m = jStat.transpose(jStat.gauss_elimination(M, q));
  111. m = jStat.multiply(m, 1 / vectorNorm(m))
  112. if (!isUnitVector(m)) break; // avoid Inf / NaN error
  113. q = m;
  114. }
  115. eigenvectors[i] = jStat.transpose(q);
  116.  
  117. }
  118. r1[1] = r1[1].map(v => vn * v);
  119. return r1;
  120. };
  121.  
  122.  
  123.  
  124. })();
  125.  
  126.  
  127. jStat.PCA = function PCA(X) {
  128. var m = X.length;
  129. var n = X[0].length;
  130. var i = 0;
  131. var j, temp1;
  132. var u = [];
  133. var D = [];
  134. var result = [];
  135. var temp2 = [];
  136. var Y = [];
  137. var Bt = [];
  138. var B = [];
  139. var C = [];
  140. var V = [];
  141. var Vt = [];
  142. for (i = 0; i < m; i++) {
  143. u[i] = jStat.sum(X[i]) / n;
  144. }
  145. for (i = 0; i < n; i++) {
  146. B[i] = [];
  147. for (j = 0; j < m; j++) {
  148. B[i][j] = X[j][i] - u[j];
  149. }
  150. }
  151. B = jStat.transpose(B);
  152. for (i = 0; i < m; i++) {
  153. C[i] = [];
  154. for (j = 0; j < m; j++) {
  155. C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);
  156. }
  157. }
  158. result = jStat.jacobi(C);
  159. V = result[0];
  160. D = result[1];
  161.  
  162. Vt = jStat.transpose(V);
  163.  
  164.  
  165. let vd = [];
  166. for (i = 0; i < D.length; i++) {
  167. vd[i] = {
  168. Vt: Vt[i],
  169. D: D[i],
  170. k: D[i] * D[i]
  171. };
  172. }
  173.  
  174. vd.sort((a, b) => {
  175. return b.k - a.k
  176. })
  177.  
  178. Vt = vd.map(e => e.Vt);
  179. D = vd.map(e => e.D);
  180.  
  181.  
  182.  
  183. V = null;
  184.  
  185.  
  186. Bt = jStat.transpose(B);
  187.  
  188. let pcs_11 = [];
  189. let pt_11 = [1, 1];
  190. for (i = 0; i < m; i++) {
  191.  
  192.  
  193. pcs_11[i] = jStat.dot([Vt[i]], [pt_11]);
  194. if (pcs_11[i] < 0) Vt[i] = jStat.multiply(Vt[i], -1);
  195. pcs_11[i] = jStat.dot([Vt[i]], [pt_11]);
  196. }
  197.  
  198.  
  199.  
  200.  
  201.  
  202. for (i = 0; i < m; i++) {
  203. Y[i] = [];
  204. for (j = 0; j < Bt.length; j++) {
  205. Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);
  206. }
  207. }
  208. return [X, D, Vt, Y];
  209. };
  210.  
  211. (function () {
  212. 'use strict';
  213.  
  214. let input = document.querySelector('form input[name="q"]');
  215. if (!(input instanceof HTMLInputElement)) return;
  216. let form = input.closest('form');
  217. if (!(form instanceof HTMLFormElement)) return;
  218.  
  219.  
  220. let locales = [...document.querySelectorAll('select#language-selector-locale > option')].map(x => x.value)
  221.  
  222. document.head.appendChild(document.createElement('style')).textContent = `
  223.  
  224.  
  225. @keyframes rs1tmAnimation {
  226. 0% {
  227. background-position-x: 3px;
  228. }
  229. 100% {
  230. background-position-x: 4px;
  231. }
  232. }
  233.  
  234. form.rs1tm{
  235. position: fixed;
  236. top:-300px;
  237. left:-300px;
  238. width: 1px;
  239. height: 1px;
  240. contain: strict;
  241. display: flex;
  242. overflow: hidden;
  243. animation: rs1tmAnimation 1ms linear 1ms 1 normal forwards;
  244. }
  245.  
  246. `
  247. document.addEventListener('animationstart', (evt) => {
  248.  
  249. if (evt.animationName === 'rs1tmAnimation') {
  250. const target = evt.target;
  251. target && target.parentNode && target.remove();
  252. }
  253.  
  254. }, true);
  255.  
  256. window.callback947 = function (rainijpolynomialRegressionJs) {
  257. if (!rainijpolynomialRegressionJs) return;
  258. const { PolynomialFeatures, PolynomialRegressor, RegressionError } = rainijpolynomialRegressionJs;
  259. if (!PolynomialFeatures || !PolynomialRegressor || !RegressionError) return;
  260.  
  261. console.log(rainijpolynomialRegressionJs)
  262. }
  263.  
  264. form.addEventListener('submit', function (evt) {
  265.  
  266. try {
  267.  
  268.  
  269. let form = evt.target;
  270. if (!(form instanceof HTMLFormElement)) return;
  271. let input = form.querySelector('input[name="q"]');
  272. if (!(input instanceof HTMLInputElement)) return;
  273.  
  274. if (form.classList.contains('rs1tm')) return;
  275.  
  276. let value = input.value;
  277. const lang = document.documentElement.lang || '';
  278.  
  279. let useLang = false;
  280.  
  281.  
  282. let u = 0;
  283. let isGoogleSearch = false;
  284.  
  285. let sites = [];
  286.  
  287. const split = value.split(/\s+/);
  288. let forceLang = 'all';
  289. let reformedSplit = [];
  290. for (const s of split) {
  291.  
  292. if (!isGoogleSearch && /^[a-z][a-z0-9_-]{2,}(\.[a-z][a-z0-9_-]{2,})*(\.[a-z-]{2,4})+$/.test(s)) {
  293. sites.push(s);
  294. } else if (s === 'js') {
  295. forceLang = 'js'; reformedSplit.push(s);
  296. } else if (s === 'css') {
  297. forceLang = 'css'; reformedSplit.push(s);
  298. } else if (s === 'user.js') {
  299. forceLang = 'js';
  300. } else if (s === 'user.css') {
  301. forceLang = 'css';
  302. } else if (s === '"js"') {
  303. reformedSplit.push('js');
  304. } else if (s === '"css"') {
  305. reformedSplit.push('css');
  306. } else if (u === 0 && s === 'g') {
  307. isGoogleSearch = true;
  308. } else if (locales.indexOf(s) >= 0 || s === lang) {
  309. useLang = s;
  310. } else {
  311. reformedSplit.push(s);
  312. }
  313. u++;
  314. }
  315. console.log(sites)
  316.  
  317. value = reformedSplit.join(' ')
  318.  
  319. let onlySite = '';
  320.  
  321. if (sites.length === 1 && sites[0]) {
  322. onlySite = sites[0];
  323. }
  324.  
  325. /*
  326. if (!isGoogleSearch && onlySite && /\.\w+\.\w+/.test(onlySite)) {
  327. alert('Greasy Fork镜像 only lists eTLD+1.');
  328. evt.preventDefault();
  329. evt.stopImmediatePropagation();
  330. evt.stopPropagation();
  331. return;
  332. }
  333. */
  334.  
  335.  
  336. if (isGoogleSearch && value) {
  337. let q = value.replace('g ', '');
  338.  
  339. let m = "-inurl%3A%22%2Fusers%2F%22+-inurl%3A%22%2Fdiscussions%22-inurl%3A%22%2Fstats%22+-inurl%3A%22%2Ffeedback%22+-inurl%3A%22%2Fcode%22+-inurl%3A%22q%3D%22+-inurl%3A%22%2Fby-site%2F%22+inurl%3A%22%2Fscripts%2F%22+site%3Agf.qytechs.cn";
  340.  
  341.  
  342.  
  343. let lr = useLang ? `&lr=lang_${useLang}` : '';
  344. evt.preventDefault();
  345. evt.stopImmediatePropagation();
  346. evt.stopPropagation();
  347. location.href = `https://www.google.com/search?q=${encodeURIComponent(q)}+${m}${lr}`
  348.  
  349. } else if (!isGoogleSearch && (value || onlySite)) {
  350.  
  351.  
  352. let newForm = document.createElement('form');
  353. newForm.className = 'rs1tm';
  354. const copyAttr = (x) => {
  355. let t = form.getAttribute(x);
  356. if (typeof t === 'string') newForm.setAttribute(x, t);
  357. }
  358. copyAttr('action');
  359. copyAttr('accept-charset');
  360. copyAttr('method');
  361. newForm.innerHTML = `<input name="q" type="hidden" value="" /><input name="site" type="hidden" /><input name="language" type="hidden" value="all" /><input name="sort" type="hidden" />`
  362.  
  363.  
  364. const nq = newForm.querySelector('input[name="q"]');
  365. const language = newForm.querySelector('input[name="language"]');
  366. const site = newForm.querySelector('input[name="site"]');
  367. const sort = newForm.querySelector('input[name="sort"]');
  368.  
  369. value = value.replace(/\s+/g, ' ');
  370. site.value = onlySite;
  371.  
  372. if (form.getAttribute('action') === `/${lang}/scripts` && useLang && useLang !== lang) {
  373. form.setAttribute('action', `/${useLang}/scripts`)
  374. }
  375.  
  376.  
  377. if (site.value === '') site.remove();
  378.  
  379. nq.value = value;
  380.  
  381. language.value = forceLang;
  382.  
  383. if (language.value === '') language.remove();
  384.  
  385.  
  386. sort.value = 'updated';
  387.  
  388. let sorting = document.querySelector('#script-list-sort');
  389. if (sorting) {
  390. let sorts1 = {
  391. nil: 0,
  392. daily_installs: 0,
  393. total_installs: 0,
  394. ratings: 0,
  395. created: 0,
  396. updated: 0,
  397. name: 0
  398. }
  399. let sorts2 = {
  400. daily_installs: 0,
  401. total_installs: 0,
  402. ratings: 0,
  403. created: 0,
  404. updated: 0,
  405. name: 0
  406. }
  407. const allOptions = sorting.querySelectorAll('.list-option');
  408. const sorts = allOptions.length === 6 ? (sorts2) : (sorts1);
  409. const keys = Object.keys(sorts)
  410.  
  411. if (allOptions.length === keys.length) {
  412.  
  413.  
  414. for (const key of keys) {
  415. let e = `.list-option:not(.list-current) a[href$="sort=${key}"]`
  416. if (key === 'nil') {
  417. e = `.list-option:not(.list-current) a[href]:not([href*="sort="])`
  418. e = sorting.querySelector(e)
  419. } else {
  420. e = sorting.querySelector(e)
  421. }
  422.  
  423. if (e) {
  424. sorts[key] = 1;
  425. }
  426.  
  427. }
  428.  
  429.  
  430.  
  431. let p = Object.entries(sorts).filter(r => !r[1])
  432. if (p.length === 1) {
  433. sort.value = p[0][0]
  434. }
  435.  
  436. }
  437.  
  438. }
  439.  
  440.  
  441.  
  442.  
  443. if (sort.value === '') sort.remove();
  444.  
  445. evt.preventDefault();
  446. evt.stopImmediatePropagation();
  447. evt.stopPropagation();
  448.  
  449. form.parentNode.insertBefore(newForm, form);
  450. newForm.submit();
  451. Promise.resolve().then(() => {
  452. newForm.remove();
  453. })
  454.  
  455.  
  456. } else {
  457. evt.preventDefault();
  458. evt.stopImmediatePropagation();
  459. evt.stopPropagation();
  460. }
  461.  
  462. } catch (e) {
  463. console.log(e);
  464.  
  465. evt.preventDefault();
  466. evt.stopImmediatePropagation();
  467. evt.stopPropagation();
  468. }
  469.  
  470. })
  471.  
  472. // Your code here...
  473. })();
  474.  
  475. (() => {
  476.  
  477. function prettyMatrix(A) {
  478. let w = '';
  479. for (let i = 0; i < A.length; i++) {
  480. for (let j = 0; j < A[i].length; j++) {
  481. w += A[i][j].toFixed(4) + '\t'
  482. }
  483. w += '\n\t';
  484. }
  485. return '[\n\t' + w.trim() + '\n]';
  486. }
  487.  
  488.  
  489. setTimeout(() => {
  490.  
  491. if ((location.search.includes('sort=updated') || location.search.includes('sort=created')) && location.pathname.endsWith('/scripts')) { } else return;
  492. let items = document.querySelectorAll('[data-script-id][data-script-daily-installs][data-script-total-installs]');
  493.  
  494. let data = [...items].map(e => ({
  495. id: parseInt(e.getAttribute('data-script-id')),
  496. daily: parseInt(e.getAttribute('data-script-daily-installs')),
  497. total: parseInt(e.getAttribute('data-script-total-installs'))
  498. })).filter(e => e.id && !isNaN(e.daily) && !isNaN(e.total));
  499.  
  500. const daily = data.map(d => d.daily);
  501. const total = data.map(d => d.total);
  502. dailyMean = jStat.mean(daily);
  503. dailySD = jStat.stdev(daily, true);
  504. totalMean = jStat.mean(total);
  505. totalSD = jStat.stdev(total, true);
  506.  
  507. const uDaily = jStat.multiply(jStat.subtract(daily, dailyMean), 1 / dailySD);
  508. const uTotal = jStat.multiply(jStat.subtract(total, totalMean), 1 / totalSD);
  509.  
  510. let dataA = data.map((d, i) => [uDaily[i], uTotal[i]]);
  511.  
  512. // dataA = dataA.slice(0, 4)
  513. // console.log(dataA)
  514.  
  515. let matrixA = jStat.transpose(dataA)
  516.  
  517.  
  518. const result = jStat.PCA(matrixA);
  519. const [X, D, Vt, Y] = result;
  520.  
  521.  
  522.  
  523. let q = null;
  524. let qSet = null;
  525. if (location.search.includes('q=')) {
  526. q = new URLSearchParams(location.search)
  527. q = q.get('q')
  528.  
  529. }
  530.  
  531. function makeQA(q) {
  532. let qSet = new Set();
  533. q.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  534. qSet.add(_.toLowerCase())
  535. });
  536. return qSet;
  537. }
  538.  
  539. if (q) {
  540. qSet = makeQA(q);
  541. }
  542.  
  543. let mr = new Map();
  544. let u = 0;
  545. for (const d of data) {
  546. d.pcaScore = Y[0][u++];
  547. let elm = document.querySelector(`[data-script-id="${d.id}"]`);
  548. if (elm) {
  549.  
  550. let order = 0;
  551. order -= Math.floor(d.pcaScore * 1000);
  552.  
  553. let u1 = 0, u2 = 0;
  554.  
  555. if (qSet) {
  556.  
  557. const pSet = qSet;
  558.  
  559. let elp = elm.querySelector('.script-link')
  560. if (elp) {
  561. let t = elp.textContent
  562.  
  563. t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  564. if (pSet.has(_.toLowerCase())) u1++;
  565. });
  566.  
  567.  
  568. }
  569.  
  570.  
  571.  
  572. let elq = elm.querySelector('.script-description')
  573.  
  574. if (elq) {
  575. let t = elq.textContent
  576.  
  577. t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  578. if (pSet.has(_.toLowerCase())) u2++;
  579. });
  580.  
  581.  
  582. }
  583.  
  584.  
  585. }
  586.  
  587.  
  588. if (u1 && u2) order -= 30000
  589. else if (u1) order -= 20000
  590. else if (u2) order -= 10000
  591.  
  592.  
  593. mr.set(d.id, order);
  594. // elm.style.order = order;
  595. // elm.parentNode.style.display = 'flex';
  596.  
  597.  
  598. // elm.parentNode.style.flexDirection = 'column';
  599.  
  600.  
  601. }
  602. }
  603.  
  604.  
  605. let lists = [...new Set([...document.querySelectorAll(`[data-script-id]`)].map(p => p.parentNode))];
  606. for (const list of lists) {
  607.  
  608. let m = [...list.childNodes].map(e => ({
  609. element: e,
  610. order: mr.get(e instanceof HTMLElement ? (+e.getAttribute('data-script-id') || '') : '') || 0
  611. }));
  612.  
  613. m.sort((a, b) => {
  614. return Math.round(a.order - b.order)
  615. });
  616. let newNodes = m.map(e => e.element);
  617.  
  618. list.replaceChildren(...newNodes);
  619. }
  620.  
  621.  
  622. // console.log(prettyMatrix(X))
  623.  
  624. // console.log(prettyMatrix(Y))
  625.  
  626.  
  627.  
  628.  
  629.  
  630. }, 300);
  631.  
  632.  
  633.  
  634. })();

QingJ © 2025

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