GreasyFork Search

To search scripts using Google Search

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         GreasyFork Search
// @namespace    http://tampermonkey.net/
// @version      0.6.3
// @description  To search scripts using Google Search
// @author       CY Fung
// @match        https://greasyfork.org/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
// @require      https://fastly.jsdelivr.net/npm/[email protected]/dist/jstat.min.js
// @grant        none
// @license MIT
// ==/UserScript==



(() => {



    function jacobi(a) {
        var n = a.length;
        var trial = n * n * 2;
        var e = jStat.identity(n, n);
        var ev = [];
        var i, j, p, q, maxim, s;
        let vaildResult = false;
        outer: while (trial-- > 0) {
            maxim = a[0][1];
            p = 0;
            q = 1;
            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++) {
                    if (i != j) {
                        let t = Math.abs(a[i][j]);
                        if (maxim < t) {
                            maxim = t;
                            p = i;
                            q = j
                        }
                    }
                }
            }

            s = jStat.identity(n, n);

            let tanValue = 2 * a[p][q] / (a[p][p] - a[q][q]);

            let cosTwoTheta = Math.sqrt(1 / (1 + tanValue * tanValue));
            let cosTheta = Math.sqrt(.5 * (1 + cosTwoTheta));
            let sinTheta = Math.sqrt(.5 * (1 - cosTwoTheta));

            s[p][p] = cosTheta;
            s[p][q] = -sinTheta;
            s[q][p] = sinTheta;
            s[q][q] = cosTheta;

            e = jStat.multiply(e, s);
            a = jStat.multiply(jStat.multiply(jStat.transpose(s), a), s);

            for (i = 0; i < n; i++) {
                for (j = i + 1; j < n; j++) {
                    if (Math.abs(a[i][j]) > .0004) {
                        continue outer;
                    }
                }
            }

            vaildResult = true;
            break;
        }
        if (!vaildResult) {
            console.warn("The matrix is not symmetric.")
            return null;
        }
        for (i = 0; i < n; i++) ev.push(a[i][i]);
        //returns both the eigenvalue and eigenmatrix
        return [e, ev];
    }



    function getVN(A) {
        // normalized the matrix values such that det(A) will be a finite value close to 1.0
        // vn = sqrt( ( column_vector_1 ^2 + column_vector_2 ^2 + ... + column_vector_n ^2 ) / n )
        let vn = 0;
        const AT = jStat.transpose(A);
        let N = AT.length;
        for (let i = 0; i < N; i++) {
            vn += jStat.dot(AT[i], AT[i]);
        }
        vn = Math.sqrt(vn / N);
        return vn;
    }

    function subtractLambdaFromDiagonal(matrix, lambda) {
        // A - lambda I
        return matrix.map((row, rowIndex) => row.map((val, colIndex) => rowIndex === colIndex ? val - lambda : val));
    }


    function eigenvalueNewton(A, lambda0) {
        const N = A.length;
        const epsilon = 1e-5; // epsilon is applied on the normalized scale of lambda
        const maxTrial = 8;

        function f(lambda) {
            return jStat.det(subtractLambdaFromDiagonal(A, lambda));
        }

        function fPrime(lambda) {
            return (f(lambda + epsilon) - f(lambda)) / epsilon;
        }

        let x_k = lambda0;
        let positiveSign = 0;
        let negativeSign = 0;
        for (let i = 0; i < maxTrial; i++) {
            const fx = f(x_k);
            const fxPrime = fPrime(x_k);
            const diff = fx / fxPrime;
            if (isNaN(diff)) return x_k; // ignore f/f'
            const x_k1 = x_k - diff;
            if ((diff > 0 ? diff : -diff) < epsilon) {
                return x_k1;
            }
            x_k = x_k1;
            if (fx > 0) positiveSign = 1;
            else if (fx < 0) negativeSign = 1;
        }
        return positiveSign && negativeSign ? x_k : lambda0; // avoid diverging iterations
    }

    function vectorNorm(v) {
        // Math.sqrt(v dot v), same as jStat.norm(jStat.transpose(v))
        let s = 0;
        for (const k of v) s += k[0] * k[0];
        return Math.sqrt(s);
    }

    function isUnitVector(v, tol = 0.01) {
        // Check if it is likely a unit vector
        let s = 0;
        for (const k of v) {
            s += k[0] * k[0];
            if (s > 1 + tol) return false;
        }
        return s > 1 - tol;
    }

    jStat.jacobiOri = jStat.jacobi;
    // https://www.statskingdom.com/pca-calculator.html
    jStat.jacobi = function (C) {

        const vn = getVN(C);
        C = jStat.multiply(C, 1 / vn);
        let r1 = jacobi(C);
        // let r0 = JSON.parse(JSON.stringify(r1))
        // r0[1] = r0[1].map(v => vn * v);
        let A = C;
        let eigenvectors = r1[0];
        let eigenvalues = r1[1];
        const iterationCount = 4;

        for (let i = 0; i < eigenvalues.length; i++) {
            let q, m;
            q = jStat.transpose(eigenvectors[i]);
            if (!isUnitVector(q)) break;
            eigenvalues[i] = eigenvalueNewton(A, eigenvalues[i]); // refine eigenvalues obtained in jacobiOri

            // inverse power method (A-lambda I) y_k = b_{k-1}
            // b_k = y_k / norm(y_k)
            let M = subtractLambdaFromDiagonal(A, eigenvalues[i]);
            for (let j = 0; j < iterationCount; j++) {
                m = jStat.transpose(jStat.gauss_elimination(M, q));
                m = jStat.multiply(m, 1 / vectorNorm(m))
                if (!isUnitVector(m)) break; // avoid Inf / NaN error
                q = m;
            }
            eigenvectors[i] = jStat.transpose(q);

        }
        r1[1] = r1[1].map(v => vn * v);
        return r1;
    };



})();


jStat.PCA = function PCA(X) {
    var m = X.length;
    var n = X[0].length;
    var i = 0;
    var j, temp1;
    var u = [];
    var D = [];
    var result = [];
    var temp2 = [];
    var Y = [];
    var Bt = [];
    var B = [];
    var C = [];
    var V = [];
    var Vt = [];
    for (i = 0; i < m; i++) {
        u[i] = jStat.sum(X[i]) / n;
    }
    for (i = 0; i < n; i++) {
        B[i] = [];
        for (j = 0; j < m; j++) {
            B[i][j] = X[j][i] - u[j];
        }
    }
    B = jStat.transpose(B);
    for (i = 0; i < m; i++) {
        C[i] = [];
        for (j = 0; j < m; j++) {
            C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);
        }
    }
    result = jStat.jacobi(C);
    V = result[0];
    D = result[1];

    Vt = jStat.transpose(V);


    let vd = [];
    for (i = 0; i < D.length; i++) {
        vd[i] = {
            Vt: Vt[i],
            D: D[i],
            k: D[i] * D[i]
        };
    }

    vd.sort((a, b) => {
        return b.k - a.k
    })

    Vt = vd.map(e => e.Vt);
    D = vd.map(e => e.D);



    V = null;


    Bt = jStat.transpose(B);

    let pcs_11 = [];
    let pt_11 = [1, 1];
    for (i = 0; i < m; i++) {


        pcs_11[i] = jStat.dot([Vt[i]], [pt_11]);
        if (pcs_11[i] < 0) Vt[i] = jStat.multiply(Vt[i], -1);
        pcs_11[i] = jStat.dot([Vt[i]], [pt_11]);
    }





    for (i = 0; i < m; i++) {
        Y[i] = [];
        for (j = 0; j < Bt.length; j++) {
            Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);
        }
    }
    return [X, D, Vt, Y];
};

(function () {
    'use strict';

    let input = document.querySelector('form input[name="q"]');
    if (!(input instanceof HTMLInputElement)) return;
    let form = input.closest('form');
    if (!(form instanceof HTMLFormElement)) return;


    let locales = [...document.querySelectorAll('select#language-selector-locale > option')].map(x => x.value)

    document.head.appendChild(document.createElement('style')).textContent = `


    @keyframes rs1tmAnimation {
        0% {
            background-position-x: 3px;
        }
        100% {
            background-position-x: 4px;
        }
    }

    form.rs1tm{
        position: fixed;
        top:-300px;
        left:-300px;
        width: 1px;
        height: 1px;
        contain: strict;
        display: flex;
        overflow: hidden;
        animation: rs1tmAnimation 1ms linear 1ms 1 normal forwards;
    }

    `
    document.addEventListener('animationstart', (evt) => {

        if (evt.animationName === 'rs1tmAnimation') {
            const target = evt.target;
            target && target.parentNode && target.remove();
        }

    }, true);

    window.callback947 = function (rainijpolynomialRegressionJs) {
        if (!rainijpolynomialRegressionJs) return;
        const { PolynomialFeatures, PolynomialRegressor, RegressionError } = rainijpolynomialRegressionJs;
        if (!PolynomialFeatures || !PolynomialRegressor || !RegressionError) return;

        console.log(rainijpolynomialRegressionJs)
    }

    form.addEventListener('submit', function (evt) {

        try {


            let form = evt.target;
            if (!(form instanceof HTMLFormElement)) return;
            let input = form.querySelector('input[name="q"]');
            if (!(input instanceof HTMLInputElement)) return;

            if (form.classList.contains('rs1tm')) return;

            let value = input.value;
            const lang = document.documentElement.lang || '';

            let useLang = false;


            let u = 0;
            let isGoogleSearch = false;

            let sites = [];

            const split = value.split(/\s+/);
            let forceLang = 'all';
            let reformedSplit = [];
            for (const s of split) {

                if (!isGoogleSearch && /^[a-z][a-z0-9_-]{2,}(\.[a-z][a-z0-9_-]{2,})*(\.[a-z-]{2,4})+$/.test(s)) {
                    sites.push(s);
                } else if (s === 'js') {
                    forceLang = 'js'; reformedSplit.push(s);
                } else if (s === 'css') {
                    forceLang = 'css'; reformedSplit.push(s);
                } else if (s === 'user.js') {
                    forceLang = 'js';
                } else if (s === 'user.css') {
                    forceLang = 'css';
                } else if (s === '"js"') {
                    reformedSplit.push('js');
                } else if (s === '"css"') {
                    reformedSplit.push('css');
                } else if (u === 0 && s === 'g') {
                    isGoogleSearch = true;
                } else if (locales.indexOf(s) >= 0 || s === lang) {
                    useLang = s;
                } else {
                    reformedSplit.push(s);
                }
                u++;
            }
            console.log(sites)

            value = reformedSplit.join(' ')

            let onlySite = '';

            if (sites.length === 1 && sites[0]) {
                onlySite = sites[0];
            }

            /*
              if (!isGoogleSearch && onlySite && /\.\w+\.\w+/.test(onlySite)) {
                  alert('Greasy Fork only lists eTLD+1.');
                      evt.preventDefault();
                  evt.stopImmediatePropagation();
                  evt.stopPropagation();
                  return;
              }
              */


            if (isGoogleSearch && value) {
                let q = value.replace('g ', '');

                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%3Agreasyfork.org";



                let lr = useLang ? `&lr=lang_${useLang}` : '';
                evt.preventDefault();
                evt.stopImmediatePropagation();
                evt.stopPropagation();
                location.href = `https://www.google.com/search?q=${encodeURIComponent(q)}+${m}${lr}`

            } else if (!isGoogleSearch && (value || onlySite)) {


                let newForm = document.createElement('form');
                newForm.className = 'rs1tm';
                const copyAttr = (x) => {
                    let t = form.getAttribute(x);
                    if (typeof t === 'string') newForm.setAttribute(x, t);
                }
                copyAttr('action');
                copyAttr('accept-charset');
                copyAttr('method');
                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" />`


                const nq = newForm.querySelector('input[name="q"]');
                const language = newForm.querySelector('input[name="language"]');
                const site = newForm.querySelector('input[name="site"]');
                const sort = newForm.querySelector('input[name="sort"]');

                value = value.replace(/\s+/g, ' ');
                site.value = onlySite;

                if (form.getAttribute('action') === `/${lang}/scripts` && useLang && useLang !== lang) {
                    form.setAttribute('action', `/${useLang}/scripts`)
                }


                if (site.value === '') site.remove();

                nq.value = value;

                language.value = forceLang;

                if (language.value === '') language.remove();


                sort.value = 'updated';

                let sorting = document.querySelector('#script-list-sort');
                if (sorting) {
                    let sorts1 = {
                        nil: 0,
                        daily_installs: 0,
                        total_installs: 0,
                        ratings: 0,
                        created: 0,
                        updated: 0,
                        name: 0
                    }
                    let sorts2 = {
                        daily_installs: 0,
                        total_installs: 0,
                        ratings: 0,
                        created: 0,
                        updated: 0,
                        name: 0
                    }
                    const allOptions = sorting.querySelectorAll('.list-option');
                    const sorts = allOptions.length === 6 ? (sorts2) : (sorts1);
                    const keys = Object.keys(sorts)

                    if (allOptions.length === keys.length) {


                        for (const key of keys) {
                            let e = `.list-option:not(.list-current) a[href$="sort=${key}"]`
                            if (key === 'nil') {
                                e = `.list-option:not(.list-current) a[href]:not([href*="sort="])`
                                e = sorting.querySelector(e)
                            } else {
                                e = sorting.querySelector(e)
                            }

                            if (e) {
                                sorts[key] = 1;
                            }

                        }



                        let p = Object.entries(sorts).filter(r => !r[1])
                        if (p.length === 1) {
                            sort.value = p[0][0]
                        }

                    }

                }




                if (sort.value === '') sort.remove();

                evt.preventDefault();
                evt.stopImmediatePropagation();
                evt.stopPropagation();

                form.parentNode.insertBefore(newForm, form);
                newForm.submit();
                Promise.resolve().then(() => {
                    newForm.remove();
                })


            } else {
                evt.preventDefault();
                evt.stopImmediatePropagation();
                evt.stopPropagation();
            }

        } catch (e) {
            console.log(e);

            evt.preventDefault();
            evt.stopImmediatePropagation();
            evt.stopPropagation();
        }

    })

    // Your code here...
})();

(() => {

    function prettyMatrix(A) {
        let w = '';
        for (let i = 0; i < A.length; i++) {
            for (let j = 0; j < A[i].length; j++) {
                w += A[i][j].toFixed(4) + '\t'
            }
            w += '\n\t';
        }
        return '[\n\t' + w.trim() + '\n]';
    }


    requestAnimationFrame(()=>{

        setTimeout(() => {

            if ((location.search.includes('sort=updated') || location.search.includes('sort=created')) && location.pathname.endsWith('/scripts')) { } else return;
            let items = document.querySelectorAll('[data-script-id][data-script-daily-installs][data-script-total-installs]');
    
            let data = [...items].map(e => ({
                id: parseInt(e.getAttribute('data-script-id')),
                daily: parseInt(e.getAttribute('data-script-daily-installs')),
                total: parseInt(e.getAttribute('data-script-total-installs'))
            })).filter(e => e.id && !isNaN(e.daily) && !isNaN(e.total));
    
            const daily = data.map(d => d.daily);
            const total = data.map(d => d.total);
            dailyMean = jStat.mean(daily);
            dailySD = jStat.stdev(daily, true);
            totalMean = jStat.mean(total);
            totalSD = jStat.stdev(total, true);
    
            const uDaily = jStat.multiply(jStat.subtract(daily, dailyMean), 1 / dailySD);
            const uTotal = jStat.multiply(jStat.subtract(total, totalMean), 1 / totalSD);
    
            let dataA = data.map((d, i) => [uDaily[i], uTotal[i]]);
    
            // dataA = dataA.slice(0, 4)
            // console.log(dataA)
    
            let matrixA = jStat.transpose(dataA)
    
    
            const result = jStat.PCA(matrixA);
            const [X, D, Vt, Y] = result;
    
    
    
            let q = null;
            let qSet = null;
            if (location.search.includes('q=')) {
                q = new URLSearchParams(location.search)
                q = q.get('q')
    
            }
    
            function makeQA(q) {
                let qSet = new Set();
                q.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
                    qSet.add(_.toLowerCase())
                });
                return qSet;
            }
    
            if (q) {
                qSet = makeQA(q);
            }
    
            let mr = new Map();
            let u = 0;
            for (const d of data) {
                d.pcaScore = Y[0][u++];
                let elm = document.querySelector(`[data-script-id="${d.id}"]`);
                if (elm) {
    
                    let order = 0;
                    order -= Math.floor(d.pcaScore * 1000);
    
                    let u1 = 0, u2 = 0;
    
                    if (qSet) {
    
                        const pSet = qSet;
    
                        let elp = elm.querySelector('.script-link')
                        if (elp) {
                            let t = elp.textContent
    
                            t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
                                if (pSet.has(_.toLowerCase())) u1++;
                            });
    
    
                        }
    
    
    
                        let elq = elm.querySelector('.script-description')
    
                        if (elq) {
                            let t = elq.textContent
    
                            t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
                                if (pSet.has(_.toLowerCase())) u2++;
                            });
    
    
                        }
    
    
                    }
    
    
                    if (u1 && u2) order -= 30000
                    else if (u1) order -= 20000
                    else if (u2) order -= 10000
    
    
                    mr.set(d.id, order);
                    // elm.style.order = order;
                    // elm.parentNode.style.display = 'flex';
    
    
                    // elm.parentNode.style.flexDirection = 'column';
    
    
                }
            }
    
    
            let lists = [...new Set([...document.querySelectorAll(`[data-script-id]`)].map(p => p.parentNode))];
            for (const list of lists) {
    
                let m = [...list.childNodes].map(e => ({
                    element: e,
                    order: mr.get(e instanceof HTMLElement ? (+e.getAttribute('data-script-id') || '') : '') || 0
                }));
    
                m.sort((a, b) => {
                    return Math.round(a.order - b.order)
                });
                let newNodes = m.map(e => e.element);
    
                list.replaceChildren(...newNodes);
            }
    
    
            // console.log(prettyMatrix(X))
    
            // console.log(prettyMatrix(Y))
    
    
    
    
    
        }, 300);

    });



})();