Discord HIT Export

Export HIT information for Discord chat

  1. // ==UserScript==
  2. // @name Discord HIT Export
  3. // @description Export HIT information for Discord chat
  4. // @version 1.01
  5. // @include https://www.mturk.com/mturk/findhits*
  6. // @include https://www.mturk.com/mturk/viewhits*
  7. // @include https://www.mturk.com/mturk/sorthits*
  8. // @include https://www.mturk.com/mturk/searchbar*selectedSearchType=hitgroups*
  9. // @include https://www.mturk.com/mturk/viewsearchbar*selectedSearchType=hitgroups*
  10. // @include https://www.mturk.com/mturk/sortsearchbar*HITGroup*
  11. // @include https://www.mturk.com/mturk/preview*
  12. // @exclude https://www.mturk.com/mturk/findhits?*hit_scraper*
  13. // @grant GM_setClipboard
  14. // @author Alden McLaren (Based on IRC Export by Cristo + clickhappier)
  15. // @namespace facebook.com/groups/mturkmembers
  16. // ==/UserScript==
  17.  
  18.  
  19. // v3.0c notes:
  20. // modified by clickhappier to reformat output in more logical ordering/separating/labeling,
  21. // since I thought it was unnecessarily unclear to read with the separators in the middle of each
  22. // type of information (label, value, separator, relevant url) instead of between the different types,
  23. // and wanted to be clearer about what the TO values represented;
  24. // also wanted to remove unnecessary linebreaks in the output that caused it to spread one HIT's info
  25. // across several IRC comments, which made it hard to tell where one HIT's info stopped and another began
  26. // (though after the version I initially modified, Cristo did later do away with all but one linebreak);
  27. // also fixed Amazon fiddling with HIT name cell contents after Oct 20, 2014 change;
  28. // also fixed Turkopticon mirror API domain to keep working after Oct 27, 2014 change
  29.  
  30.  
  31. var accountStatus = "loggedOut";
  32. if ( !document.getElementById("lnkWorkerSignin") ) // if sign-in link not present
  33. {
  34. accountStatus = "loggedIn";
  35. }
  36.  
  37.  
  38. function getUrlVariable(url, variable)
  39. {
  40. var query = url.split('?');
  41. var vars = query[1].split("&");
  42. for ( var i=0; i<vars.length; i++ )
  43. {
  44. var pair = vars[i].split("=");
  45. if ( pair[0] == variable )
  46. { return pair[1]; }
  47. }
  48. return(false);
  49. }
  50.  
  51.  
  52. var caps = document.getElementsByClassName('capsulelink');
  53. for (var c = 0; c < caps.length/2; c++){
  54. var button = document.createElement('button');
  55. button.setAttribute("place",c);
  56. button.textContent = 'CORD';
  57. button.style.height = '14px';
  58. button.style.width = '30px';
  59. button.style.fontSize = '8px';
  60. button.style.border = '1px solid';
  61. button.style.padding = '0px';
  62. button.style.backgroundColor = 'transparent';
  63. button.title = 'Click to save HIT information to your clipboard. Please wait while shortened URLs are retrieved.';
  64. button.addEventListener("click", display, false);
  65. document.getElementById('capsule'+c+'-0').parentNode.appendChild(button);
  66. }
  67.  
  68. function getTO(f){
  69. var toComp = [];
  70. var toUrl = 'https://mturk-api.istrack.in/multi-attrs.php?ids='+f;
  71. var toUrl2 = 'https://turkopticon.ucsd.edu/api/multi-attrs.php?ids='+f;
  72. var requestTO = new XMLHttpRequest();
  73. try{ // first try main TO server
  74. requestTO.onreadystatechange = function () {
  75. if ((requestTO.readyState ===4) && (requestTO.status ===200)) {
  76. if (requestTO.responseText.split(':').length > 2) {
  77. var toInfo = requestTO.responseText.split('{')[3].split('}')[0].split(',');
  78. for (var t = 0; t < 4; t++) {
  79. var arrTo = toInfo[t].split(':');
  80. toComp.push(arrTo[1].substring(1,4));
  81. }
  82. }
  83. else { toComp = ['-','-','-','-']; }
  84. }
  85. };
  86. requestTO.open('GET', toUrl2, false);
  87. requestTO.send(null);
  88. return toComp;
  89. }
  90. catch(err){ // if main TO server unavailable, try Miku's TO mirror server (istrack.in)
  91. try{
  92. requestTO.onreadystatechange = function () {
  93. if ((requestTO.readyState ===4) && (requestTO.status ===200)) {
  94. if (requestTO.responseText.split(':').length > 2) {
  95. var toInfo = requestTO.responseText.split('{')[3].split('}')[0].split(',');
  96. for (var t = 0; t < 4; t++) {
  97. var arrTo = toInfo[t].split(':');
  98. toComp.push(arrTo[1].substring(1,4));
  99. }
  100. }
  101. else { toComp = ['-','-','-','-']; }
  102. }
  103. };
  104. requestTO.open('GET', toUrl, false);
  105. requestTO.send(null);
  106. return toComp;
  107. }
  108. catch(err){ // if both unavailable, return 'na's
  109. toComp = ['na','na','na','na'];
  110. return toComp;
  111. }
  112. }
  113. }
  114.  
  115. function sleep(ms){ // from http://www.digimantra.com/tutorials/sleep-or-wait-function-in-javascript/
  116. var dt = new Date();
  117. dt.setTime(dt.getTime() + ms);
  118. while (new Date().getTime() < dt.getTime());
  119. }
  120.  
  121. function ns4tBulkShorten(urlArr){
  122. console.log("ns4tBulkShorten function");
  123. var shortUrl;
  124. var shortUrlsSplit = [];
  125. var urlT = "https://ns4t.net/yourls-api.php?action=bulkshortener&title=MTurk&signature=39f6cf4959";
  126. for (var i = 0; i < urlArr.length; i++)
  127. {
  128. urlT += "&urls[]="+encodeURIComponent(urlArr[i]);
  129. }
  130. console.log(urlT);
  131. var requestNs4tBulk = new XMLHttpRequest();
  132. try{
  133. requestNs4tBulk.onreadystatechange = function () {
  134. if (requestNs4tBulk.readyState == 4) {
  135. if (requestNs4tBulk.status == 200) {
  136. shortUrl = requestNs4tBulk.responseText;
  137. console.log("ns4t.net Bulk response: " + requestNs4tBulk.status + " " + requestNs4tBulk.statusText + " " + requestNs4tBulk.responseText);
  138. }
  139. else {
  140. console.log('ns4t.net Bulk unsuccessful: ' + requestNs4tBulk.status + " " + requestNs4tBulk.statusText);
  141. }
  142. }
  143. };
  144. requestNs4tBulk.open('GET', urlT, false);
  145. requestNs4tBulk.send(null);
  146. shortUrlsSplit = shortUrl.split(";");
  147.  
  148. if ( urlArr.length == 4 ) // if preview/panda links were available
  149. {
  150. return {preview:shortUrlsSplit[0], panda:shortUrlsSplit[1], req:shortUrlsSplit[2], to:shortUrlsSplit[3]};
  151. }
  152. else if ( urlArr.length == 2 ) // if preview/panda links were unavailable due to being logged out
  153. {
  154. return {preview:"(url n/a)", panda:"(url n/a)", req:shortUrlsSplit[0], to:shortUrlsSplit[1]};
  155. }
  156. else // no reason to not have either 4 or 2 links, but just in case...
  157. {
  158. return null; // return null value to revert to one-by-one shortening
  159. }
  160. }
  161. catch(err){
  162. return shortUrl; // return null value to revert to one-by-one shortening
  163. }
  164. }
  165. function ns4tShorten(url){ // mturk-only URL shortener on Tjololo's server ns4t.net
  166. console.log("ns4tShorten function");
  167. var shortUrl;
  168. var urlT = "https://ns4t.net/yourls-api.php" + "?action=shorturl&url=" + encodeURIComponent(url) + "&format=simple&title=MTurk&signature=39f6cf4959";
  169. var requestNs4t = new XMLHttpRequest();
  170. try{
  171. requestNs4t.onreadystatechange = function () {
  172. if (requestNs4t.readyState == 4) {
  173. if (requestNs4t.status == 200) {
  174. shortUrl = requestNs4t.responseText;
  175. console.log("ns4t.net response: " + requestNs4t.status + " " + requestNs4t.statusText + " " + requestNs4t.responseText);
  176. }
  177. else {
  178. console.log('ns4t.net unsuccessful: ' + requestNs4t.status + " " + requestNs4t.statusText);
  179. }
  180. }
  181. };
  182. requestNs4t.open('GET', urlT, false);
  183. requestNs4t.send(null);
  184. return shortUrl;
  185. }
  186. catch(err){
  187. return shortUrl;
  188. }
  189. }
  190. function tnyimShorten(url){ // Tny.im URL Shortener - http://tny.im/aboutapi.php - this is only possible this way because their server has the "Access-Control-Allow-Origin = *" headers enabled (the above TO mirror server does too)
  191. console.log("tnyimShorten function");
  192. var shortUrl;
  193. var urlT = "https://tny.im/yourls-api.php" + "?action=shorturl&url=" + encodeURIComponent(url) + "&format=simple&title=MTurk";
  194. var requestTnyim = new XMLHttpRequest();
  195. try{
  196. requestTnyim.onreadystatechange = function () {
  197. if (requestTnyim.readyState == 4) {
  198. if (requestTnyim.status == 200) {
  199. shortUrl = requestTnyim.responseText;
  200. console.log("tny.im response: " + requestTnyim.status + " " + requestTnyim.statusText + " " + requestTnyim.responseText);
  201. }
  202. else {
  203. console.log('tny.im unsuccessful: ' + requestTnyim.status + " " + requestTnyim.statusText);
  204. }
  205. }
  206. };
  207. requestTnyim.open('GET', urlT, false);
  208. requestTnyim.send(null);
  209. return shortUrl;
  210. }
  211. catch(err){
  212. return shortUrl;
  213. }
  214. }
  215. function googlShorten(url){ // Goo.gl URL Shortener
  216. console.log("googlShorten function");
  217. var shortUrl;
  218. var urlG = "https://www.googleapis.com/urlshortener/v1/url";
  219. var requestGoogl = new XMLHttpRequest();
  220. try{
  221. requestGoogl.open("POST", urlG, false);
  222. requestGoogl.setRequestHeader("Content-Type", "application/json");
  223. requestGoogl.onreadystatechange = function() {
  224. if (requestGoogl.readyState == 4) {
  225. if (requestGoogl.status == 200) {
  226. shortUrl = JSON.parse(requestGoogl.response).id;
  227. console.log("goo.gl response: " + requestGoogl.status + " " + requestGoogl.statusText + " " + JSON.parse(requestGoogl.response).id );
  228. }
  229. else {
  230. console.log('goo.gl unsuccessful: ' + requestGoogl.status + " " + requestGoogl.statusText);
  231. }
  232. }
  233. };
  234. var data = new Object();
  235. data.longUrl = url;
  236. requestGoogl.send(JSON.stringify(data));
  237. return shortUrl;
  238. }
  239. catch(err){
  240. return shortUrl;
  241. }
  242. }
  243. function shortenUrl(url){
  244. sleep(500); // milliseconds delay - wait some milliseconds (currently half a second) between shortens to reduce chance of hitting usage limits
  245. var shortUrl;
  246. shortUrl = ns4tShorten(url);
  247. if ( shortUrl === undefined ) { // if you reached the ns4t.net URL shortener's temporary usage limits or the server is otherwise unavailable
  248. shortUrl = tnyimShorten(url);
  249. if ( shortUrl === undefined ) { // if you reached the tny.im URL shortener's temporary limits or the server is otherwise unavailable
  250. shortUrl = googlShorten(url);
  251. if ( shortUrl === undefined ) { // if you reached the Google URL shortener's temporary limits too or the server is otherwise unavailable
  252. shortUrl = "(x)";
  253. }
  254. }
  255. }
  256. return shortUrl;
  257. }
  258.  
  259. // output display box
  260. var ircexportdiv = document.createElement('div');
  261. var ircexporttextarea = document.createElement('textarea');
  262. ircexportdiv.style.position = 'fixed';
  263. ircexportdiv.style.width = '500px';
  264. ircexportdiv.style.height = '155px';
  265. ircexportdiv.style.left = '50%';
  266. ircexportdiv.style.right = '50%';
  267. ircexportdiv.style.margin = '-250px 0px 0px -250px';
  268. ircexportdiv.style.top = '300px';
  269. ircexportdiv.style.padding = '5px';
  270. ircexportdiv.style.border = '2px';
  271. ircexportdiv.style.backgroundColor = 'black';
  272. ircexportdiv.style.color = 'white';
  273. ircexportdiv.style.zIndex = '100';
  274. ircexportdiv.setAttribute('id','ircexport_div');
  275. ircexportdiv.style.display = 'none';
  276. ircexporttextarea.style.padding = '2px';
  277. ircexporttextarea.style.width = '500px';
  278. ircexporttextarea.style.height = '130px';
  279. ircexporttextarea.title = 'Discord Export Output';
  280. ircexporttextarea.setAttribute('id','ircexport_text');
  281. ircexportdiv.textContent = 'Discord Export: Press Ctrl+C to (re-)copy to clipboard. Click textarea to close.';
  282. ircexportdiv.style.fontSize = '12px';
  283. ircexportdiv.appendChild(ircexporttextarea);
  284. document.body.insertBefore(ircexportdiv, document.body.firstChild);
  285. ircexporttextarea.addEventListener("click", function(){ ircexportdiv.style.display = 'none'; }, false);
  286.  
  287.  
  288. function display(e){
  289. var theButton = e.target;
  290. theButton.style.backgroundColor = "#CC0000";
  291.  
  292. var capHand = document.getElementById('capsule' + theButton.getAttribute("place") + '-0');
  293. var tBodies = capHand.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
  294.  
  295. var thisReq = tBodies.getElementsByClassName('requesterIdentity')[0];
  296. var thisReqName = thisReq.textContent;
  297. var thisReqId = "unavailable"; // handle logged-out export requests now that requester ID links are unavailable as of 2015-07-20
  298. if ( accountStatus == "loggedIn" )
  299. {
  300. thisReqId = getUrlVariable(thisReq.parentNode.href, "requesterId");
  301. }
  302.  
  303. var thisTitle = capHand.textContent.trim();
  304. thisTitle = thisTitle.replace(/<(\w+)[^>]*>.*<\/\1>/gi, "").trim(); // addition to strip html tags and their contents, appearing inside the title link (re 10-20-2014 appearance of "<span class="tags"></span>")
  305.  
  306. var thisHitGroup = "unavailable"; // handle logged-out export requests for HITs with no preview/notqualified links
  307. // if hit has a preview or notqualified link
  308. var thisHitLink = capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling;
  309. if ( thisHitLink.href !== '' )
  310. {
  311. // if this is a preview link
  312. if ( thisHitLink.href.indexOf('preview') > -1 )
  313. {
  314. thisHitGroup = getUrlVariable(thisHitLink.href, "groupId");
  315. }
  316. // if this is a notqualified link
  317. else if ( thisHitLink.href.indexOf('notqualified') > -1 )
  318. {
  319. thisHitGroup = getUrlVariable(thisHitLink.href, "hitId");
  320. // Amazon messed up the notqualified links, now looking like https://www.mturk.com/mturk/notqualified?hitGroupId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX&hitId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX ; and then they flipped the order of these values on 6/2/15
  321. }
  322. // if this is a requestqualification link we shouldn't be on, but are anyway because of stuff Amazon screwed with on 6/2/15
  323. else if ( thisHitLink.href.indexOf('requestqualification') > -1 )
  324. {
  325. // go to the next link, the "(why?)" notqualified link instead
  326. thisHitGroup = getUrlVariable(thisHitLink.nextElementSibling.href, "hitId");
  327. // Amazon messed up the notqualified links, now looking like https://www.mturk.com/mturk/notqualified?hitGroupId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX&hitId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX ; and then they flipped the order of these values on 6/2/15
  328. }
  329. }
  330.  
  331. var thisReward = tBodies.getElementsByClassName('reward')[0].textContent.trim();
  332.  
  333. var thisTimeLimit = tBodies.getElementsByClassName('capsule_field_text')[2].textContent.trim();
  334.  
  335. var thisHitsAvail = "??"; // handle Amazon removing HITs Available data from logged-out view 2015-07-20
  336. if ( accountStatus == "loggedIn" )
  337. {
  338. thisHitsAvail = tBodies.getElementsByClassName('capsule_field_text')[4].textContent.trim();
  339. }
  340.  
  341. var thisQualTable = document.getElementById('capsule'+theButton.getAttribute("place")+'target').getElementsByTagName('tbody')[2];
  342. if ( document.location.href.indexOf('?last_hits_previewed') > -1 ) // for compatibility with mmmturkeybacon Last Hits Previewed
  343. {
  344. thisQualTable = document.getElementById('capsule'+theButton.getAttribute("place")+'target').getElementsByTagName('tbody')[1];
  345. }
  346. var thisQualRows = thisQualTable.getElementsByTagName('td');
  347. var qualStart = 3; // standard starting row
  348. if ( accountStatus == "loggedOut" ) // handle logged-out export requests - difference in qual table coding
  349. {
  350. qualStart = 1;
  351. }
  352. if ( document.location.href.indexOf('?last_hits_previewed') > -1 ) // for compatibility with mmmturkeybacon Last Hits Previewed
  353. {
  354. qualStart = 2;
  355. }
  356. var masterQual = '';
  357. for ( var m = qualStart; m < thisQualRows.length; m++ )
  358. {
  359. if ( thisQualRows[m].textContent.indexOf('Masters') > -1 )
  360. {
  361. masterQual = '@Masters :poop: ';
  362. }
  363. }
  364.  
  365. var urlsToShorten = [];
  366.  
  367. var thisPreviewUrl = "(url n/a)";
  368. var thisPandaUrl = "(url n/a)";
  369. if ( thisHitGroup != "unavailable" ) // handle logged-out export requests for HITs with no preview/notqualified links - fallback to default "(url n/a)" text
  370. {
  371. //thisPreviewUrl = shortenUrl('https://www.mturk.com/mturk/preview?groupId=' + thisHitGroup);
  372. urlsToShorten.push('https://www.mturk.com/mturk/preview?groupId=' + thisHitGroup);
  373. //thisPandaUrl = shortenUrl('https://www.mturk.com/mturk/previewandaccept?groupId=' + thisHitGroup);
  374. urlsToShorten.push('https://www.mturk.com/mturk/previewandaccept?groupId=' + thisHitGroup);
  375. }
  376.  
  377. var thisReqUrl = "(url n/a)";
  378. if ( thisReqId != "unavailable" )
  379. {
  380. //thisReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + thisReqId);
  381. urlsToShorten.push('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + thisReqId);
  382. }
  383. else if ( thisReqId == "unavailable" ) // handle 2015-07-20 loss of logged-out requester ids - fallback to search by name
  384. {
  385. //thisReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&searchWords=' + thisReqName.replace(/ /g, "+") ) + " (search)";
  386. urlsToShorten.push('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&searchWords=' + thisReqName.replace(/ /g, "+") );
  387. }
  388.  
  389. var thisTOUrl = "(url n/a)";
  390. var thisTOStats = "??";
  391. if ( thisReqId != "unavailable" )
  392. {
  393. //thisTOUrl = shortenUrl('http://turkopticon.ucsd.edu/' + thisReqId);
  394. urlsToShorten.push('http://turkopticon.ucsd.edu/' + thisReqId);
  395. thisTOStats = getTO(thisReqId);
  396. }
  397. else if ( thisReqId == "unavailable" ) // handle 2015-07-20 loss of logged-out requester ids - fallback to search by name
  398. {
  399. //thisTOUrl = shortenUrl('https://turkopticon.ucsd.edu/main/php_search?query=' + thisReqName.replace(/ /g, "+") ) + " (search)";
  400. urlsToShorten.push('https://turkopticon.ucsd.edu/main/php_search?query=' + thisReqName.replace(/ /g, "+"));
  401. }
  402.  
  403. var shortUrlsBulkResults = ns4tBulkShorten(urlsToShorten);
  404. console.log(shortUrlsBulkResults);
  405. if (shortUrlsBulkResults) // if bulk shorten via ns4t.net is successful
  406. {
  407. thisPreviewUrl = shortUrlsBulkResults["preview"];
  408. thisPandaUrl = shortUrlsBulkResults["panda"];
  409. thisReqUrl = shortUrlsBulkResults["req"];
  410. thisTOUrl = shortUrlsBulkResults["to"];
  411. if ( thisReqId == "unavailable" )
  412. {
  413. thisTOUrl += " (search)";
  414. thisReqUrl += " (search)";
  415. }
  416. }
  417. else // if bulk shorten is unsuccessful, revert to original shortening functions
  418. {
  419. if ( thisHitGroup != "unavailable" ) // handle logged-out export requests for HITs with no preview/notqualified links - fallback to default "(url n/a)" text
  420. {
  421. thisPreviewUrl = shortenUrl('https://www.mturk.com/mturk/preview?groupId=' + thisHitGroup);
  422. thisPandaUrl = shortenUrl('https://www.mturk.com/mturk/previewandaccept?groupId=' + thisHitGroup);
  423. }
  424.  
  425. if ( thisReqId != "unavailable" )
  426. {
  427. thisReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + thisReqId);
  428. thisTOUrl = shortenUrl('http://turkopticon.ucsd.edu/' + thisReqId);
  429. }
  430. else if ( thisReqId == "unavailable" ) // handle 2015-07-20 loss of logged-out requester ids - fallback to search by name
  431. {
  432. thisReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&searchWords=' + thisReqName.replace(/ /g, "+") ) + " (search)";
  433. thisTOUrl = shortenUrl('https://turkopticon.ucsd.edu/main/php_search?query=' + thisReqName.replace(/ /g, "+") ) + " (search)";
  434. }
  435. }
  436.  
  437. // when the URL shortener service is unavailable but the preview link is available, add the full-length preview link at the end
  438. var shortUrlUnav = '';
  439. if ( (thisPreviewUrl == "(x)") && (thisHitGroup != "unavailable") )
  440. {
  441. shortUrlUnav = " \r\n^ https://www.mturk.com/mturk/preview?groupId=" + thisHitGroup;
  442. }
  443.  
  444. var exportOutput = "";
  445. var loggedOutApology = " (Info missing since logged out.)";
  446. if ( accountStatus == "loggedIn" )
  447. {
  448. exportOutput = '@HITs ' + masterQual + ' :moneybag: :moneybag: :moneybag: ' + '\n' + '**Requester:** ' + thisReqName + ' • ' + ' ' + thisReqUrl + '\n' + '**Title**: ' + thisTitle + ' ' + ' • ' + thisPreviewUrl + '\n' + '**Pay**: ' + thisReward + ' **Avail**: ' + thisHitsAvail + ' **Limit**: ' + thisTimeLimit + '\n' + '**TO**: ' + 'Pay='+thisTOStats[1] + ' Fair='+thisTOStats[2] + ' Comm='+thisTOStats[0] + ' ' + ' • ' + thisTOUrl + '\n' + '**PandA**: ' + thisPandaUrl + shortUrlUnav ;
  449. }
  450. else if ( accountStatus == "loggedOut" )
  451. {
  452. exportOutput = '@HITs ' + masterQual + ' :moneybag: :moneybag: :moneybag: ' + '\n' + '**Requester:** ' + thisReqName + ' • ' + ' ' + thisReqUrl + '\n' + '**Title**: ' + thisTitle + ' ' + ' • ' + thisPreviewUrl + '\n' + '**Pay**: ' + thisReward + ' **Avail**: ' + thisHitsAvail + ' **Limit**: ' + thisTimeLimit + '\n' + 'TO: ?? ' + thisTOUrl + ' • ' + 'PandA: ' + thisPandaUrl + loggedOutApology + shortUrlUnav ;
  453. }
  454.  
  455. if (GM_setClipboard) { GM_setClipboard(exportOutput); }
  456. window.setTimeout(function(){ theButton.style.backgroundColor = 'transparent'; }, 500);
  457. ircexporttextarea.textContent = exportOutput;
  458. ircexportdiv.style.display = 'block';
  459. ircexporttextarea.select();
  460. }

QingJ © 2025

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