Greasy Fork is available in English.

Greasy Fork API

Get information from Greasy Fork and do actions in it.

بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greatest.deepsurf.us/scripts/445697/1244619/Greasy%20Fork%20API.js

  1. // ==UserScript==
  2. // @name Greasy Fork API
  3. // @namespace -
  4. // @version 2.0.1
  5. // @description Get information from Greasy Fork and do actions in it.
  6. // @author NotYou
  7. // @license LGPL-3.0
  8. // @connect greatest.deepsurf.us
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM.xmlHttpRequest
  11. // @grant GM_openInTab
  12. // @grant GM.openInTab
  13. // ==/UserScript==
  14.  
  15. class GreasyFork {
  16. constructor() {
  17. if(location.hostname === 'greatest.deepsurf.us' || location.hostname === 'sleazyfork.org') {
  18. this.host = location.host
  19. return
  20. }
  21.  
  22. throw new Error('Invalid instance initialization location, host is not valid.')
  23. }
  24.  
  25. static get __xmlHttpRequest() {
  26. return GM_xmlhttpRequest || GM.xmlHttpRequest
  27. }
  28.  
  29. static get __openInTab() {
  30. return GM_openInTab || GM.openInTab
  31. }
  32.  
  33. static get INVALID_ARGUMENT_ERROR() {
  34. return 'Argument "{0}" is not valid'
  35. }
  36.  
  37. static get PARSING_ERROR() {
  38. return 'Unexpected parsing error, "{0}"'
  39. }
  40.  
  41. static get INVALID_PAGE_ERROR() {
  42. return 'Current page is not valid'
  43. }
  44.  
  45. static __format(str, ...args) {
  46. let result = str
  47.  
  48. for (let i = 0; i < args.length; i++) {
  49. const arg = args[i]
  50.  
  51. result = result.replace(new RegExp(`\\{${i}\\}`, 'g'), arg)
  52. }
  53.  
  54. return result
  55. }
  56.  
  57. static __isId(id) {
  58. return typeof id === 'string' && /^\d+$/.test(id)
  59. }
  60.  
  61. static get languages() {
  62. return [
  63. 'ar', 'bg', 'cs', 'da', 'de', 'el', 'en', 'eo', 'es', 'fi', 'fr', 'fr-CA', 'he', 'hu', 'id', 'it', 'ja', 'ka', 'ko', 'nb', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sr', 'sv', 'th', 'tr', 'uk', 'ug', 'vi', 'zh-CN', 'zh-TW'
  64. ]
  65. }
  66.  
  67. static get version() {
  68. return '2.0.1'
  69. }
  70.  
  71. static parseScriptNode(node) {
  72. if (!(node instanceof HTMLElement) || !node.dataset.scriptId) {
  73. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'node'))
  74. }
  75.  
  76. const {
  77. scriptId,
  78. scriptName,
  79. scriptAuthors,
  80. scriptDailyInstalls,
  81. scriptTotalInstalls,
  82. scriptRatingScore,
  83. scriptCreatedDate,
  84. scriptUpdatedDate,
  85. scriptType,
  86. scriptVersion,
  87. sensitive,
  88. scriptLanguage,
  89. cssAvailableAsJs
  90. } = node.dataset
  91.  
  92. const ratingsNode = node.querySelector('dd.script-list-ratings')
  93. let ratings = {}
  94.  
  95. if(ratingsNode) {
  96. const ratingsGood = Number(ratingsNode.querySelector('.good-rating-count').textContent)
  97. const ratingsOk = Number(ratingsNode.querySelector('.ok-rating-count').textContent)
  98. const ratingsBad = Number(ratingsNode.querySelector('.bad-rating-count').textContent)
  99.  
  100. ratings = {
  101. ratingsGood,
  102. ratingsOk,
  103. ratingsBad
  104. }
  105. }
  106.  
  107. return Object.assign({
  108. scriptId,
  109. scriptName,
  110. scriptAuthors: JSON.parse(scriptAuthors),
  111. scriptDailyInstalls: Number(scriptDailyInstalls),
  112. scriptTotalInstalls: Number(scriptTotalInstalls),
  113. scriptRatingScore: Number(scriptRatingScore),
  114. scriptCreatedDate,
  115. scriptUpdatedDate,
  116. scriptType,
  117. scriptVersion,
  118. sensitive: sensitive === 'true',
  119. scriptLanguage,
  120. cssAvailableAsJs: cssAvailableAsJs === 'true',
  121. node
  122. }, ratings)
  123. }
  124.  
  125. static parseScriptMetadata(code) {
  126. if (typeof code !== 'string') {
  127. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'code'))
  128. }
  129.  
  130. const reScriptMetadata = /\/\/ ==UserScript==\n(.*?[\s\S]+)\n\/\/ ==\/UserScript==/
  131. const matched = code.match(reScriptMetadata)
  132.  
  133. if (!Boolean(matched)) {
  134. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'code'))
  135. }
  136.  
  137. const metadataResponse = {}
  138. const metadata = matched[1]
  139.  
  140. const metadataChunks = metadata.split('\n')
  141.  
  142. for (let i = 0; i < metadataChunks.length; i++) {
  143. const metadataChunk = metadataChunks[i]
  144.  
  145. try {
  146. const { metaKey, metaValue } = metadataChunk.match(/\/\/ @(?<metaKey>[a-zA-Z\-\d\:]+)\s+(?<metaValue>.+)/).groups
  147.  
  148. metadataResponse[metaKey] = metaValue
  149. } catch(error) {
  150. throw new Error(GreasyFork.__format(GreasyFork.PARSING_ERROR, error))
  151. }
  152. }
  153.  
  154. return metadataResponse
  155. }
  156.  
  157. static getScriptData(id) {
  158. if (!GreasyFork.__isId(id)) {
  159. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  160. }
  161.  
  162. return new Promise((res, rej) => {
  163. GreasyFork.__xmlHttpRequest({
  164. url: `https://greatest.deepsurf.us/scripts/${id}.json`,
  165. onload: response => {
  166. const data = JSON.parse(response.responseText)
  167.  
  168. return res(data)
  169. },
  170. onerror: err => {
  171. return rej(err)
  172. }
  173. })
  174. })
  175. }
  176.  
  177. static getScriptCode(id, isLibrary = false) {
  178. if (!GreasyFork.__isId(id)) {
  179. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  180. }
  181.  
  182. const url = `https://greatest.deepsurf.us/scripts/${id}/code/userscript` + (isLibrary ? '.js' : '.user.js')
  183.  
  184. return new Promise((res, rej) => {
  185. GreasyFork.__xmlHttpRequest({
  186. url,
  187. onload: response => {
  188. const code = response.responseText
  189.  
  190. return res(code)
  191. },
  192. onerror: err => {
  193. return rej(err)
  194. }
  195. })
  196. })
  197. }
  198.  
  199. static getScriptHistory(id) {
  200. if (!GreasyFork.__isId(id)) {
  201. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  202. }
  203.  
  204. return new Promise((res, rej) => {
  205. GreasyFork.__xmlHttpRequest({
  206. url: `https://greatest.deepsurf.us/scripts/${id}/versions.json`,
  207. onload: response => {
  208. const data = JSON.parse(response.responseText)
  209.  
  210. return res(data)
  211. },
  212. onerror: err => {
  213. return rej(err)
  214. }
  215. })
  216. })
  217. }
  218.  
  219. static getScriptStats(id) {
  220. if (!GreasyFork.__isId(id)) {
  221. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  222. }
  223.  
  224. return new Promise((res, rej) => {
  225. GreasyFork.__xmlHttpRequest({
  226. url: `https://greatest.deepsurf.us/scripts/${id}/stats.json`,
  227. onload: response => {
  228. const data = JSON.parse(response.responseText)
  229.  
  230. return res(data)
  231. },
  232. onerror: err => {
  233. return rej(err)
  234. }
  235. })
  236. })
  237. }
  238.  
  239. static getScriptSet(id, page = 1) {
  240. if (!GreasyFork.__isId(id)) {
  241. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  242. }
  243.  
  244. if (typeof page !== 'number') {
  245. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'page'))
  246. }
  247.  
  248. return new Promise((res, rej) => {
  249. GreasyFork.__xmlHttpRequest({
  250. url: `https://greatest.deepsurf.us/scripts.json?set=${id}&page=${page}&filter_locale=0`,
  251. onload: response => {
  252. const data = JSON.parse(response.responseText)
  253.  
  254. return res(data)
  255. },
  256. onerror: err => {
  257. return rej(err)
  258. }
  259. })
  260. })
  261. }
  262.  
  263. static getUserData(id) {
  264. if (!GreasyFork.__isId(id)) {
  265. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  266. }
  267.  
  268. return new Promise((res, rej) => {
  269. GreasyFork.__xmlHttpRequest({
  270. url: `https://greatest.deepsurf.us/users/${id}.json`,
  271. onload: response => {
  272. const data = JSON.parse(response.responseText)
  273.  
  274. return res(data)
  275. },
  276. onerror: err => {
  277. return rej(err)
  278. }
  279. })
  280. })
  281. }
  282.  
  283. static searchScripts(query, page = 1) {
  284. if (typeof query !== 'string') {
  285. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'query'))
  286. }
  287.  
  288. if (typeof page !== 'number') {
  289. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'page'))
  290. }
  291.  
  292. return new Promise((res, rej) => {
  293. GreasyFork.__xmlHttpRequest({
  294. url: `https://greatest.deepsurf.us/scripts.json?q=${query}&page=${page}`,
  295. onload: response => {
  296. const data = JSON.parse(response.responseText)
  297.  
  298. return res(data)
  299. },
  300. onerror: err => {
  301. console.error(err)
  302. return rej([])
  303. }
  304. })
  305. })
  306. }
  307.  
  308. static searchUsers(query, page = 1) {
  309. if (typeof query !== 'string') {
  310. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'query'))
  311. }
  312.  
  313. if (typeof page !== 'number') {
  314. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'page'))
  315. }
  316.  
  317. return new Promise((res, rej) => {
  318. GreasyFork.__xmlHttpRequest({
  319. url: `https://greatest.deepsurf.us/users.json?q=${query}&page=${page}`,
  320. onload: response => {
  321. const data = JSON.parse(response.responseText)
  322.  
  323. return res(data)
  324. },
  325. onerror: err => {
  326. console.error(err)
  327. return rej([])
  328. }
  329. })
  330. })
  331. }
  332.  
  333. static installScript(id, type = 'js') {
  334. if (!GreasyFork.__isId(id)) {
  335. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'id'))
  336. }
  337.  
  338. if (type !== 'js' && type !== 'css') {
  339. throw new Error(GreasyFork.__format(GreasyFork.INVALID_ARGUMENT_ERROR, 'type'))
  340. }
  341.  
  342. const URL = `https://greatest.deepsurf.us/scripts/${id}/code/userscript.user.${type}`
  343.  
  344. GreasyFork.__openInTab(URL)
  345. }
  346.  
  347. listScripts() {
  348. const scriptList = document.querySelector('.script-list')
  349.  
  350. if (scriptList === null) {
  351. throw new Error(GreasyFork.INVALID_PAGE_ERROR)
  352. }
  353.  
  354. const userScripts = scriptList.querySelectorAll('[data-script-id]')
  355. const result = []
  356. const typeMap = {
  357. 'browse-script-list': 'browse',
  358. 'user-script-list': 'user'
  359. }
  360. const type = typeMap[scriptList.id] || 'unknown'
  361.  
  362. for (let i = 0; i < userScripts.length; i++) {
  363. const userScript = userScripts[i]
  364.  
  365. result.push(
  366. GreasyFork.parseScriptNode(userScript)
  367. )
  368. }
  369.  
  370. return {
  371. type,
  372. list: result
  373. }
  374. }
  375.  
  376. signOut() {
  377. GreasyFork.__xmlHttpRequest({
  378. url: `https://${this.host}/users/sign_out`
  379. })
  380. }
  381. }