您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Parse information on gf.qytechs.cn
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/445697/1055427/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或关注我们的公众号极客氢云获取最新地址