Greasy Fork镜像 API

Parse information on gf.qytechs.cn

目前為 2022-05-29 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/445697/1055428/Greasy%20Fork%20API.js

// ==UserScript==
// @name Greasy Fork镜像 API
// @namespace -
// @version 1.0.0
// @description Parse information on gf.qytechs.cn
// @author NotYou
// @license LGPL-3.0
// @grant none
// ==/UserScript==

/*
"Program" is a set of instructions that a computer uses to perform a specific function.
"Library" is a program that is embedded in other programs.
"This library" refers to "Greasy Fork镜像 API" library.
"Account" is an arrangement in which a person uses the Internet or email services of a particular company, organization or individual person's web resource.
"I" refers to individual person that owns internet account "NotYou" at web resource "gf.qytechs.cn".

I does not responsible for any
damage caused by this library
*/

/*
TODO:
- [x] Feedback
- [ ] Convesations
- [ ] Versions
*/

class GreasyFork {
    error(errorable, message) {
        if(!errorable) throw new Error(message)
    }

    languages() {
        return [
            'ar', 'bg', 'cs', 'da', 'de', 'el', 'en', 'eo', 'es', 'fi', 'fr', 'fr-CA', 'he', 'hu', 'id', 'it', 'ja', 'ko', 'nb', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sr', 'sv', 'th', 'tr', 'uk', 'ug', 'vi', 'zh-CN', 'zh-TW'
        ]
    }

    parseScriptElement(i) {
        if(!i||!i.dataset.scriptAuthors) return null
        let _ = null,
            data = i.dataset,
            rating = i.children[0].children[1].children[7] ? i.children[0].children[1].children[7].children[0].innerText.split('\n').join(' ').split(' ') : _,
            scriptLink = i.children[0].children[0].children[0] ? i.children[0].children[0].children[0].href : _,
            source = !scriptLink ? _ : data.scriptType == 'library' ? scriptLink.slice(0, scriptLink.indexOf('-'))+'/code/index.js' : scriptLink.slice(0, scriptLink.indexOf('-'))+'/code/script.user.js'
        return {
            name: data.scriptName,
            id: +(data.scriptId),
            version: data.scriptVersion,
            lang: data.scriptLanguage,
            installs: +(data.scriptTotalInstalls),
            dailyInstalls: +(data.scriptDailyInstalls),
            rating: +(data.scriptRatingScore),
            ratingGood: rating ? rating[0] == '0' ? 0 : +(rating[0]) : _,
            ratingOk: rating ? rating[1] == '0' ? 0 : +(rating[1]) : _,
            ratingBad: rating ? rating[2] == '0' ? 0 : +(rating[2]) : _,
            authors: JSON.parse(data.scriptAuthors) || data.scriptAuthors.replaceAll('"', '"'),
            createDate: data.scriptCreatedDate,
            updateDate: data.scriptUpdatedDate,
            type: data.scriptType,
            cssAsJs: data.cssAvailableAsJs == 'true' ? true : false,
            sensitive: data.sensitive == 'true' ? true : false,
            element: i,
            url: scriptLink,
            source: source
        }
    }

    parseScriptCodeMeta(code) {
        if(typeof code != 'string'||!code.match(/\/\/ ==UserScript==/)) return null
        var arr = code.replaceAll('\n', '').match(/\/\/ ==UserScript==.*\/\/ ==\/UserScript==/)[0].split('// ')
        for (let i = 0; i < 2; i++) arr.shift()
        arr.pop()
        let result = []
        for (let i of arr) {
            let data = i.replace(/ . +/, ' ').split(' ')
            let name = data[0]
            data.shift()
            let value = data.join(' ')
            result.push({
                meta: name,
                value: value
            })
        }
        return result
    }

    ls() {
        function ls(id) {
            if(document.querySelector(`#${id}`)) {
                let result = []
                for (let i of document.querySelector(`#${id}`).children) {
                    result.push(new GreasyFork().parseScriptElement(i))
                }
                return result
            } return null
        }
        return {
            scripts: ls('user-script-list'),
            browsed: ls('browse-script-list'),
            libraries: ls('user-library-script-list')
        }
    }

    get(q) {
        let parser = new DOMParser(),
            error = new GreasyFork().error,
            langs = new GreasyFork().languages(),
            str = str => str.replaceAll('\n', '').replaceAll(' ', ''),
            _ = null

        return {
            script(query = q) {
                let errMsg = 'Argument 1 is not defined'
                return {
                    async asJSON(id = query || q) {
                        error(id, errMsg)
                        return fetch(`https://gf.qytechs.cn/scripts/${id}.json`).then((r) =>
                             r.json()
                        ).then((c) => {
                            return c
                        })
                    },
                    async code(id = query || q) {
                        error(id, errMsg)
                        return fetch(`https://gf.qytechs.cn/scripts/${id}/code`).then((r) =>
                            r.text()
                        ).then((c) => {
                            return parser.parseFromString(c, 'text/html').querySelector('pre').innerText
                        })
                    },
                    async history(id = query || q) {
                        error(id, errMsg)
                        return fetch(`https://gf.qytechs.cn/scripts/${id}/versions`).then((r) =>
                            r.text()
                        ).then((c) => {
                            let list = parser.parseFromString(c, 'text/html').querySelectorAll('.history_versions li'), result = []
                            for (let i of list) {
                                let ver = i.children[1].children[0],
                                    time = i.children[2],
                                    log = i.children[3]

                                result.push({
                                    version: {
                                        id: +(ver.href.match(/\?version=\d.+/)[0].replace('?version=', '')),
                                        text: ver.innerText,
                                        url: ver.href
                                    },
                                    time: {
                                        text: time.innerText,
                                        iso:  time.attributes.datetime.value
                                    },
                                    changelog: log ? {
                                        html: log.innerHTML,
                                        text: log.innerText
                                    } : _
                                })
                            }
                            return result
                        })
                    },
                    async feedback(id = query || q) {
                        error(id, errMsg)
                        return fetch(`https://gf.qytechs.cn/scripts/${id}/feedback`).then((r) =>
                            r.text()
                        ).then((c) => {
                            let list = parser.parseFromString(c, 'text/html').querySelectorAll('.discussion-list-container'), result = []
                            for (let i of list) {
                                let di = i.children[0],
                                    ti = di.children[1],
                                    mt = di.children[0],
                                    mt0 = mt.children[0],
                                    mt1 = mt.children[1],
                                    a0 = mt0.children[0],
                                    a1 = mt1.children[0].children[0],
                                    url = ti.href,
                                    last = mt1.children[0].children

                                result.push({
                                    id: +(url.match(/ns\/\d.+/)[0].replace('ns/', '')),
                                    url: url,
                                    rating: ti.children[0].classList.contains('rating-icon') ? ti.children[0].innerText : _,
                                    text: ti.children[1] ? ti.children[1].innerText.replace('\n        ', '').replace('\n      ', '') : ti.children[0].innerText.replace('\n        ', '').replace('\n      ', ''),
                                    meta: {
                                        first: {
                                            id: +(a0.href.match(/\d.+-/)[0].replace(/-.+/, '').replace('-', '')),
                                            url: a0.href,
                                            nickname: a0.innerText
                                        },
                                        last: {
                                            id: +(a1.href.match(/\d.+-/)[0].replace(/-.+/, '').replace('-', '')),
                                            url: a1.href,
                                            nickname: a1.innerText
                                        },
                                        time: {
                                            first: {
                                                iso: mt0.children[1].attributes.datetime.value,
                                                text: mt0.children[1].innerText
                                            },
                                            last: last[last.length-1].attributes.datetime ? {
                                                iso:  last[last.length-1].attributes.datetime.value,
                                                text: last[last.length-1].innerText
                                            } : _
                                        }
                                    }
                                })
                            }
                            return result.length > 1 ? result : _
                        })
                    },
                    async stats(id = query || q) {
                        error(id, errMsg)
                        return fetch(`https://gf.qytechs.cn/scripts/${id}/stats.json`).then((r) =>
                            r.json()
                        ).then((c) => {
                            return c
                        })
                    },
                    async info(id = query || q, options = {}) {
                        error(id, errMsg)
                        return fetch(str(`https://gf.qytechs.cn/
                        ${options.locale && langs.includes(options.locale) ? options.locale : 'en'}
                        /scripts/${id}${options.locale ? `&locale_override=1` : ''}`)).then((r) =>
                            r.text()
                        ).then((c) => {
                            let doc = parser.parseFromString(c, 'text/html'),
                                screenshots = _,
                                addInfo = _,
                                appliesTo = [],
                                comp = _,
                                support = doc.querySelector('#script-feedback-suggestion').children.length == 3 ? support = doc.querySelector('#script-feedback-suggestion').children[0].href : _,
                                getInfo = value => doc.querySelector(`dd.script-${value}`),
                                license = getInfo('show-license'),
                                d_installs = getInfo('show-daily-installs') ? +(getInfo('show-daily-installs').innerText.replaceAll(',', '')) : _,
                                installs = getInfo('show-total-installs') ? +(getInfo('show-total-installs').innerText.replaceAll(',', '')) : _,
                                r_g = doc.querySelector('.good-rating-count') ? +(doc.querySelector('.good-rating-count').innerText) : _,
                                r_o = doc.querySelector('.ok-rating-count') ? +(doc.querySelector('.ok-rating-count').innerText) : _,
                                r_b = doc.querySelector('.bad-rating-count') ? +(doc.querySelector('.bad-rating-count').innerText) : _,
                                c_date_text = getInfo('show-created-date').innerText,
                                c_date_iso = doc.querySelector('dd.script-show-created-date').children[0].children[0].attributes.datetime.value,
                                u_date_text = getInfo('show-updated-date').innerText,
                                u_date_iso = doc.querySelector('dd.script-show-updated-date').children[0].children[0].attributes.datetime.value,
                                global = doc.querySelector('#script-info header'),
                                install = doc.querySelector('#install-area') ? doc.querySelectorAll('#install-area *:not(.install-help-link)') : _,
                                data = install ? install[0].dataset : _,
                                yours = doc.querySelector('#script-links').children,
                                require = doc.querySelector('#script-content p code') ? doc.querySelector('#script-content p code').innerText.replace('// @require ', '') : _

                            if(doc.querySelector('.user-screenshots')) {
                                screenshots = []
                                doc.querySelectorAll('.user-screenshots a').forEach((e) => {
                                    screenshots.push({
                                        source: e.href,
                                        thumbnail: e.children[0].src
                                    })
                                })
                            }
                            doc.querySelectorAll('dd.script-show-applies-to li').forEach((e) => {
                                appliesTo.push(e.innerText)
                            })
                            if(doc.querySelector('.script-show-compatibility')) {
                                comp = []
                                doc.querySelectorAll('.script-show-compatibility img').forEach((e) => {
                                    comp.push({
                                        browser: e.alt.replace('Compatible with ', ''),
                                        value: e.title.replaceAll('\n', ' '),
                                    })
                                })
                            }
                            if(doc.querySelector('#additional-info')) addInfo = doc.querySelector('#additional-info')
                            return {
                                id: +(id),
                                name: global.children[0].innerText,
                                desc: global.children[1].innerText,
                                version: getInfo('show-version').innerText,
                                isYour: yours[yours.length-1].children[0].href.match(/\/admin/) ? true : false,
                                isPrevVersion: data ? data.isPreviousVersion == 'true' ? true : false : _,
                                installs: {
                                    daily: d_installs,
                                    total: installs,
                                },
                                rating: {
                                    good: r_g,
                                    ok: r_o,
                                    bad: r_b,
                                },
                                date: {
                                    created: {
                                        text: c_date_text,
                                        iso: c_date_iso,
                                    },
                                    updated: {
                                        text: u_date_text,
                                        iso: u_date_iso,
                                    }
                                },
                                license: {
                                    name: license.innerText,
                                    url: license.children[0].children[0] ? license.children[0].children[0].href : _
                                },
                                screenshots: screenshots,
                                additionalInfo: addInfo ? [
                                    {
                                        html: addInfo.innerHTML,
                                        text: addInfo.innerText
                                    }
                                ] : _,
                                appliesTo: appliesTo,
                                compatibility: comp,
                                supportUrl: support,
                                requireUrl: require
                            }
                        })
                    },
                    async set(id = query || q, options = {}) {
                        error(id, errMsg)
                        return id && fetch(str(`https://gf.qytechs.cn/
                        ${options.locale && langs.includes(options.locale) ? options.locale : 'en'}
                        /scripts?set=${id}
                        ${options.sort ? `&sort=${options.sort}` : ''}
                        ${options.page ? `&page=${options.page}` : ''}
                        ${options.localeFilter ? `&filter_locale=${options.localeFilter}` : ''}
                        ${options.locale ? `&locale_override=1` : ''}`)).then(r =>
                            r.text()
                        ).then((c) => {
                            let result = [], list = parser.parseFromString(c, 'text/html').querySelectorAll('#browse-script-list li')
                            for (let i of list) {
                                result.push(new GreasyFork().parseScriptElement(i))
                            }
                            return result
                        })
                    },
                }
            },

            async user(id = q) {
                error(id, 'Argument 1 is not defined')
                return fetch(`https://gf.qytechs.cn/users/${id}`).then((r) =>
                    r.text()
                ).then((c) => {
                    let doc = parser.parseFromString(c, 'text/html'), url = new URL(doc.baseURI)
                    return {
                        nickname: doc.querySelector('#about-user h2').firstChild.data,
                        id: +(id),
                        isMod: doc.querySelector('#about-user > h2 .badge-moderator') ? true : false,
                        scripts:  (() => {
                            if(doc.querySelector('#user-script-list')) {
                                let result = []
                                for (let i of doc.querySelector('#user-script-list').children) {
                                    result.push(new GreasyFork().parseScriptElement(i))
                                }
                                return result
                            } return _
                        })(),
                        libraries: (() => {
                            if(doc.querySelector('#user-library-script-list')) {
                                let result = []
                                for (let i of doc.querySelector('#user-library-script-list').children) {
                                    result.push(new GreasyFork().parseScriptElement(i))
                                }
                                return result
                            } return _
                        })(),
                        scriptSets: (() => {
                            if(doc.querySelector('#user-script-sets')) {
                                let result = []
                                for (let i of doc.querySelector('#user-script-sets').children) {
                                    if(i.firstChild.data === 'Favorites ') return _
                                    let data = i.firstChild.data.split(':')
                                    result.push({
                                        name: data[0],
                                        desc: data[1].replace(' ', '').split('').reverse().join('').replace(' ', '').split('').reverse().join(''),
                                        id: i.children[0].href.replace(/.*?\/scripts\?set=/, '')
                                    })
                                }
                                return result
                            } return _
                        })(),
                        recentComments: (() => {
                            if(doc.querySelectorAll('#user-discussions section ul li a')) {
                                let result = []
                                for (let i of doc.querySelectorAll('#user-discussions section ul li a')) {
                                    result.push({
                                        title: i.lastChild.innerText,
                                        id: !i.href.match(/ns\/\d+/) ? +(i.href.match(/\d+/)[0]) : +(i.href.match(/ns\/\d+/)[0].replace('ns/', '')),
                                        action: i.firstChild.data.replace(': ', ''),
                                        URL: i.href
                                    })
                                }
                                return result.length > 1 ? result : _
                            } return _
                        })()
                    }
                })
            },

            async search(query = q, type, options = {}) {
                if(typeof query != 'string') throw new Error('Argument 1 is not string')
                function searchURL(path) {
                    return str(`https://gf.qytechs.cn/
                    ${options.locale && langs.includes(options.locale) ? options.locale : 'en'}/
                    ${path}${options.asJSON == true ? '.json' : ''}?q=${query ? query : ''}
                    ${options.sort ? `&sort=${options.sort}` : ''}
                    ${options.page ? `&page=${options.page}` : ''}
                    ${options.locale ? `&locale_override=1` : ''}`)
                }
                if(type === 'script') {
                    return fetch(searchURL('scripts')).then((r) =>
                        options.asJSON == true ? r.json() : r.text()
                    ).then((c) => {
                        if(options.asJSON == true) return c
                        let result = [], list = parser.parseFromString(c, 'text/html').querySelectorAll('#browse-script-list li:not(.ad-entry)')
                        for (let i of list) {
                            result.push(new GreasyFork().parseScriptElement(i))
                        }
                        return result
                    })
                }
                if(type === 'library') {
                    return fetch(searchURL('scripts/libraries')).then((r) =>
                        options.asJSON == true ? r.json() : r.text()
                    ).then((c) => {
                        if(options.asJSON == true) return c
                        let result = [], list = parser.parseFromString(c, 'text/html').querySelectorAll('#browse-script-list li')
                        for (let i of list) {
                            result.push(new GreasyFork().parseScriptElement(i))
                        }
                        return result
                    })
                } if(type === 'user') {
                    return fetch(searchURL('users')).then((r) =>
                        options.asJSON == true ? r.json() : r.text()
                    ).then((c) => {
                        if(options.asJSON == true) return c
                        let result = [], list = parser.parseFromString(c, 'text/html').querySelectorAll('#browse-user-list li')
                        for (let i of list) {
                            result.push({
                                nickname: i.children[0].innerText,
                                id: +(i.children[0].href.replace(/.*?\/users\//, '').split('-')[0]),
                                badge: (i.children[1] ? i.children[1].innerText.toLowerCase() : 'none'),
                                url: i.children[0].href,
                                scripts: +(i.innerHTML.match(/- .+/, '')[0].match(/\d/)[0])
                            })
                        }
                        return result
                    })
                } if(type === 'list') {
                    return [
                        'script',
                        'library',
                        'user',
                        'list'
                    ]
                } else throw new Error(`Argument 1 ${type} is not defined`)
            },

            async modlog(options = {}) {
                return fetch(str(`https://gf.qytechs.cn/
                ${options.locale && langs.includes(options.locale) ? options.locale : 'en'}
                /moderator_actions
                ${options.page ? `?page=${options.page}` : '?page=1'}
                ${options.locale ? `&locale_override=1` : ''}`)).then(r =>
                    r.text()
                ).then(c => {
                    let trs = parser.parseFromString(c, 'text/html').querySelectorAll('.log-table > tbody > tr'), result = []
                    for (let i of trs) {
                        let time = i.children[0].children[0],
                            userUrl = i.children[1].children[0].href,
                            item = i.children[2].children[0],
                            res = i.children[4]

                        result.push({
                            time: {
                                text: time.innerText,
                                iso: time.attributes.datetime.value
                            },
                            mod: {
                                id: userUrl.match(/\d.+-/) ? +(userUrl.match(/\d.+-/)[0].replace('-', '')) : userUrl.match(/\d-/) ? +(userUrl.match(/\d-/)[0].replace('-', '')) : _,
                                url: userUrl,
                                nickname: i.children[1].children[0].innerText
                            },
                            item: i.children[2] ? {
                                name: item ? item.innerText : _,
                                url: item ? item.href : _,
                                type: item ? str(item.previousSibling.data.replace(': ', '')) : _
                            } : _,
                            action: i.children[3].innerText,
                            reason: {
                                name: res.innerText.replaceAll(' ', '').replaceAll('\n', ''),
                                url: res.children[0].children[0] ? res.children[0].children[0].href : _
                            }
                        })
                    }
                    return result
                })
            },
        }
    }

    async action(action, options = {}) {
        let error = new GreasyFork().error,
            parser = new DOMParser()

        if(action === 'install') {
            error(options.id, 'Argument 2 { id } is not defined')
            setTimeout(() => {
                window.open(`https://gf.qytechs.cn/scripts/${options.id}/code/source.user.${options.lang === 'css' ? 'css' : 'js'}`, '_top')
            }, options.timeout * 1e3 || 0)
        }
        if(action === 'signout') {
            setTimeout(() => {
                fetch('https://gf.qytechs.cn/users/sign_out')
            }, options.timeout * 1e3 || 0)
        } if(action === 'list') {
            return [
                'install',
                'signout',
                'list'
            ]
        }
        else throw new Error(`Argument 1 ${action} is not defined`)
    }

    version() {
        return '1.0.0'
    }
}





























QingJ © 2025

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