GreasyForkScriptUpdate

Check update for Greasyfork userscript

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

  1. /* eslint-disable no-multi-spaces */
  2. // ==UserScript==
  3. // @name GreasyForkScriptUpdate
  4. // @namespace GreasyForkScriptUpdate
  5. // @version 0.4.2
  6. // @description Check update for Greasyfork userscript
  7. // @author PY-DNG
  8. // @match http*://*/*
  9. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  10. // @grant GM_xmlhttpRequest
  11. // @grant unsafeWindow
  12. // ==/UserScript==
  13. (function () {
  14. 'use strict';
  15.  
  16. // Accessable in Global_Scope
  17. typeof(unsafeWindow) !== 'object' && (window.unsafeWindow = window);
  18. unsafeWindow.GreasyForkUpdater = GreasyForkUpdater;
  19.  
  20. // Use 'new' keyword
  21. function GreasyForkUpdater(metarule=null) {
  22. const GFU = this;
  23. const singles = metarule ? metarule.singles : [];
  24. const multiples = metarule ? metarule.multiples : [];
  25.  
  26. // Parse '// ==UserScript==\n...\n// ==/UserScript==' to {name: '', namespace: '', version: '', ...}
  27. // Returns metaData object directly
  28. GFU.parseMetaData = function(metaText) {
  29. const metaData = {};
  30. const lines = metaText.split('\n');
  31. const edgeMatcher = /==\/?UserScript==/i;
  32. const keyValueMatcher = /^\/\/ *@([^@ ]+) +(.+) *$/;
  33. const keyOnlyMatcher = /^\/\/ *@([^@ ]+) *$/;
  34. for (let line of lines) {
  35. // Get & validate line
  36. line = line.trim();
  37. if (line.match(edgeMatcher)) {continue;};
  38. if (!line.match(keyValueMatcher) && !line.match(keyOnlyMatcher)) {continue;};
  39.  
  40. // Get key-value
  41. const match = line.match(keyValueMatcher) ? line.match(keyValueMatcher) : line.match(keyOnlyMatcher);
  42. const key = match[1];
  43. const value = match[2] ? match[2] : true;
  44.  
  45. // Attach to metaData object
  46. if (singles.includes(key)) {
  47. // Single value metaitem: stores only the first value
  48. if (!metaData.hasOwnProperty(key)) {
  49. metaData[key] = value;
  50. }
  51. } else if (multiples.includes(key)) {
  52. // Multiple value metaitem: always stores all values in an array whether provided value are multiple or not
  53. if (!metaData.hasOwnProperty(key)) {
  54. metaData[key] = [value];
  55. } else {
  56. metaData[key].push(value);
  57. }
  58. } else {
  59. // Unspecificed metaitem: stores single-provided values directly and multiple-provided values in arrays
  60. if (!metaData.hasOwnProperty(key)) {
  61. metaData[key] = value;
  62. } else {
  63. if (Array.isArray(metaData[key])) {
  64. metaData[key].push(value);
  65. } else {
  66. metaData[key] = [metaData[key], value];
  67. }
  68. }
  69. }
  70. }
  71. return metaData;
  72. }
  73.  
  74. // Request latest script meta text from greasyfork
  75. // You'll get metaText string as the first argument in your callback function
  76. GFU.requestMetaText = function(scriptID, callback, args=[]) {
  77. if (!scriptID) {return false;};
  78. const url = 'https://gf.qytechs.cn/scripts/{SID}/code/script.meta.js'.replace('{SID}', String(scriptID));
  79. GM_xmlhttpRequest({
  80. method: 'GET',
  81. url: url,
  82. responseType: 'text',
  83. onload: function(e) {
  84. callback && callback.apply(null, [e.responseText].concat(args));
  85. }
  86. })
  87. }
  88.  
  89. // Request & parse latest script meta data from greasyfork
  90. // You'll get metaData object as the first argument in your callback function
  91. GFU.getMetaData = function(scriptID, callback, args=[]) {
  92. if (!scriptID) {return false;};
  93. GFU.requestMetaText(scriptID, function(metaText) {
  94. const metaData = GFU.parseMetaData(metaText);
  95. callback && callback.apply(null, [metaData].concat(args));
  96. })
  97. }
  98.  
  99. // Compare two version texts(v1, v2), returns true if v1 > v2
  100. // Returns null while version text contains Non-demical text period(s)
  101. GFU.versionNewer = function(v1, v2) {
  102. v1 = v1.trim().split('.');
  103. v2 = v2.trim().split('.');
  104.  
  105. for (let i = 0; i < Math.min(v1.length, v2.length); i++) {
  106. v1[i] = Number(v1[i]);
  107. v2[i] = Number(v2[i]);
  108. if (!v1[i] || !v2[i]) {return null;};
  109. if (v1[i] !== v2[i]) {return v1[i] > v2[i];};
  110. }
  111.  
  112. return v1.length > v2.length;
  113. }
  114.  
  115. // Check if there's new version of the script on GreasyFork using scriptID, current version text
  116. // You'll get update(bool), updateurl(string), metaData(object) as the first, second and third argument in your callback function
  117. GFU.checkUpdate = function(scriptID, curver, callback, args=[]) {
  118. if (!scriptID) {return false;};
  119. GFU.getMetaData(scriptID, function(metaData) {
  120. const update = GFU.versionNewer(metaData.version, curver);
  121. const updateurl = 'https://gf.qytechs.cn/scripts/{SID}/code/script.user.js'.replace('{SID}', String(scriptID));
  122. callback && callback.apply(null, [update, updateurl, metaData].concat(args));
  123. })
  124. }
  125.  
  126. // Check & Install update automatically
  127. GFU.update = function(scriptID, curver) {
  128. GFU.checkUpdate(scriptID, curver, function() {
  129. const url = 'https://gf.qytechs.cn/scripts/{SID}/code/script.user.js'.replace('{SID}', String(scriptID));
  130. location.href = url;
  131. })
  132. }
  133. }
  134. })();

QingJ © 2025

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