Persist

Persist Function

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/29175/189868/Persist.js

  1. // ==UserScript==
  2. // @name Persist
  3. // @namespace http://gm.wesley.eti.br
  4. // @description Persist Function
  5. // @author w35l3y
  6. // @email w35l3y@brasnet.org
  7. // @copyright 2013+, w35l3y (http://gm.wesley.eti.br)
  8. // @license GNU GPL
  9. // @homepage http://gm.wesley.eti.br
  10. // @version 1.0.1.0
  11. // @language en
  12. // @include nowhere
  13. // @exclude *
  14. // @require https://greasyfork.org/scripts/29175-xpath/code/XPath.js?version=189855
  15. // @grant GM_setValue
  16. // @grant GM_getValue
  17. // @grant GM_xmlhttpRequest
  18. // @connect *
  19. // ==/UserScript==
  20.  
  21. /**************************************************************************
  22.  
  23. This program is free software: you can redistribute it and/or modify
  24. it under the terms of the GNU General Public License as published by
  25. the Free Software Foundation, either version 3 of the License, or
  26. (at your option) any later version.
  27.  
  28. This program is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. GNU General Public License for more details.
  32.  
  33. You should have received a copy of the GNU General Public License
  34. along with this program. If not, see <http://www.gnu.org/licenses/>.
  35.  
  36. **************************************************************************/
  37.  
  38. var Persist = function (s) {
  39. var service = Persist.services[s];
  40.  
  41. this.request = function (obj) {
  42. var k,
  43. xthis = this,
  44. params = function (def) {
  45. var list = {};
  46.  
  47. this.add = function (vars) {
  48. if (vars) {
  49.  
  50. if (typeof vars == "object") {
  51. for (var k in vars) {
  52. var e = vars[k];
  53.  
  54. if (typeof e == "object" && (!/^(?:radio|checkbox)$/i.test(e.type) || e.checked)) {
  55. var n = e.name || k;
  56.  
  57. if (e.checked && /^checkbox$/i.test(e.type)) {
  58. if (n in list) {
  59. list[n].push(e.value);
  60. } else {
  61. list[n] = [e.value];
  62. }
  63. } else if ("value" in e) {
  64. list[n] = e.value;
  65. } else {
  66. list[n] = e;
  67. }
  68. } else {
  69. list[k] = e;
  70. }
  71. }
  72. } else {
  73. list = vars;
  74. }
  75. }
  76. };
  77.  
  78. this.toString = function() {
  79. if (typeof list == "object") {
  80. var data = "";
  81. for (var key in list) {
  82. if (list[key] instanceof Array) {
  83. var keyarr = key.replace(/^\s+|\s+$/g, "");
  84. if (!/\[\w*\]$/.test(key)) keyarr += "[]";
  85.  
  86. for (var k in list[key]) {
  87. var v = list[key][k];
  88. data += "&" + encodeURIComponent(keyarr) + "=" + encodeURIComponent(v);
  89. }
  90. } else {
  91. data += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(list[key]);
  92. }
  93. }
  94.  
  95. return data.substr(1);
  96. } else {
  97. return list;
  98. }
  99. };
  100. },
  101. data = new params();
  102.  
  103. data.add(obj.pdata);
  104. data.add(obj.adata);
  105. data.add(obj.data);
  106. data.add(obj.odata);
  107.  
  108. if (typeof obj.onload != "function") {
  109. obj.onload = function (obj) {
  110. console.log(["request.load", obj]);
  111. };
  112. }
  113.  
  114. if (typeof obj.onerror != "function") {
  115. obj.onerror = function (obj) {
  116. console.log(["request.error", obj]);
  117. };
  118. }
  119.  
  120. var update = function (obj, e) {
  121. obj.response = {
  122. raw : function () {return e;},
  123. text : function () {return e.responseText;},
  124. json : function () {
  125. try {
  126. return JSON.parse(e.responseText);
  127. } catch (x) {
  128. return eval("(" + e.responseText + ")");
  129. }
  130. },
  131. doc : function () {
  132. try {
  133. return new DOMParser().parseFromString(e.responseText, /^Content-Type: ([\w/]+)$/mi.test(e.responseHeaders) && RegExp.$1 || "text/html");
  134. } catch (x) {
  135. var doc = document.implementation.createHTMLDocument("");
  136. doc.documentElement.innerHTML = e.responseText;
  137.  
  138. return doc;
  139. }
  140. },
  141. };
  142. obj.value = e.responseText;
  143. },
  144. params = {
  145. url : obj.url,
  146. method : obj.method,
  147. onload : function (e) {
  148. update(obj, e);
  149.  
  150. obj[(/^2/.test(e.status)?"onload":"onerror")].apply(xthis, [obj]);
  151. },
  152. onerror : function (e) {
  153. update(obj, e);
  154.  
  155. obj.onerror.apply(xthis, [obj]);
  156. }
  157. },
  158. sdata = data.toString();
  159.  
  160. if (/^post$/i.test(obj.method)) {
  161. var p = {
  162. headers : {
  163. "Content-Type" : "application/x-www-form-urlencoded"
  164. },
  165. data : sdata,
  166. };
  167.  
  168. console.log(sdata);
  169.  
  170. for (k in p) {
  171. params[k] = p[k];
  172. }
  173. } else if (sdata) {
  174. params.url += "?" + sdata;
  175.  
  176. }
  177.  
  178. if (typeof obj.headers == "object")
  179. for (k in obj.headers) {
  180. params.headers[k] = obj.headers[k];
  181. }
  182.  
  183. return GM_xmlhttpRequest(params);
  184. };
  185.  
  186. for (var k in service) {
  187. this[k] = service[k];
  188. }
  189. };
  190.  
  191. Persist.services = {
  192. LOCAL : {
  193. write : function (obj) {
  194. var label_keys = "persist_keys-" + obj.service,
  195. label_data = "persist_data-" + obj.service,
  196. mapping = JSON.parse(GM_getValue(label_keys, "{}")),
  197. data = JSON.parse(GM_getValue(label_data, "[]")),
  198. key = obj.key;
  199.  
  200. if (key in mapping) {
  201. key = mapping[obj.key];
  202. }
  203.  
  204. if (key in data) {
  205. var tv = typeof obj.value,
  206. td = typeof data[key];
  207.  
  208. if ((td != tv) && (td == "object" || tv == "object")) {
  209. throw ["Incompatible types ", td, tv].toString();
  210. } else {
  211. switch (td) {
  212. case "string":
  213. if (-1 == obj.mode) { // prepend
  214. data[key] = obj.value + data[key];
  215. } else if (1 == obj.mode) { // append
  216. data[key] += obj.value;
  217. } else { // overwrite (default)
  218. data[key] = obj.value;
  219. }
  220. break;
  221. case "boolean":
  222. if (-1 == obj.mode) { // unused
  223. throw ["Reserved action"].toString();
  224. } else if (1 == obj.mode) { // toggle
  225. data[key] = !data[key];
  226. } else { // overwrite (default)
  227. data[key] = !!value;
  228. }
  229. break;
  230. case "number":
  231. var value = Number(obj.value);
  232.  
  233. if (-1 == obj.mode) { // subtract
  234. data[key] -= value;
  235. } else if (1 == obj.mode) { // add
  236. data[key] += value;
  237. } else { // overwrite (default)
  238. data[key] = value;
  239. }
  240. break;
  241. case "object":
  242. if (-1 == obj.mode) { // prepend
  243. for (var k in data[key]) {
  244. obj.value[k] = data[key][k];
  245. }
  246. data[key] = obj.value;
  247. } else if (1 == obj.mode) { // append
  248. for (var k in obj.value) {
  249. data[key][k] = obj.value[k];
  250. }
  251. } else { // overwrite (default)
  252. data[key] = obj.value;
  253. }
  254. break;
  255. default:
  256. throw ["Unsupported type " + td, data[key], key].toString();
  257. }
  258.  
  259. obj.value = data[key];
  260. }
  261. } else {
  262. var tkey = data.push(obj.value);
  263.  
  264. if (--tkey != key) {
  265. if ("key" in obj) {
  266. if (key in mapping) {
  267. console.log(["Wrong mapping... ", tkey, key]);
  268. }
  269.  
  270. mapping[key] = tkey;
  271. obj.key = key;
  272.  
  273. GM_setValue(label_keys, JSON.stringify(mapping));
  274. } else {
  275. obj.key = tkey;
  276. }
  277. }
  278. }
  279.  
  280. GM_setValue(label_data, JSON.stringify(data));
  281.  
  282. if (typeof obj.onload != "function") {
  283. obj.onload = function (obj) {
  284. console.log(["write.load", obj]);
  285. };
  286. }
  287.  
  288. return obj.onload.apply(this, [obj]);
  289. },
  290. delete : function (obj) {
  291. throw ["Not implemented"].toString();
  292. },
  293. read : function (obj) {
  294. var mapping = JSON.parse(GM_getValue("persist_keys-" + obj.service, "{}")),
  295. key = obj.key;
  296.  
  297. if (key in mapping) {
  298. key = mapping[key];
  299. }
  300.  
  301. obj.value = JSON.parse(GM_getValue("persist_data-" + obj.service, "[]"))[key];
  302.  
  303. if (typeof obj.onload != "function") {
  304. obj.onload = function (obj) {
  305. console.log(["read.load", obj]);
  306. };
  307. }
  308.  
  309. return obj.onload.apply(this, [obj]);
  310. },
  311. },
  312. PASTEBIN : {
  313. write : function (obj) {
  314. var execute = function (x) {
  315. var onload = x.onload,
  316. value = x.value,
  317. xthis = this,
  318. p = {
  319. url : "http://pastebin.com/api/api_post.php",
  320. method : "post",
  321. adata : JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
  322. // api_dev_key : "", // required
  323. // api_user_key : "",
  324. }))),
  325. pdata : {
  326. api_paste_format : "text",
  327. api_paste_private : "1",
  328. api_paste_expire_date : "N",
  329. api_paste_code : x.value, // required
  330. },
  331. odata : {
  332. api_paste_key : obj.key,
  333. api_option : "paste"
  334. },
  335. onload : function (y) {
  336. if (/^https?:\/\//i.test(y.value) && /\w+$/.test(y.value)) {
  337. var key = x.key;
  338. x.key = RegExp["$&"];
  339.  
  340. x.onload = onload;
  341. x.value = value;
  342.  
  343. x.onload.apply(xthis, [x]);
  344.  
  345. if (x.read) {
  346. /* It is implemented that way because currently there isn't an EDIT option via API */
  347. y.key = key;
  348. y.onload = function (z) {
  349. console.log(["delete.load", z]);
  350. };
  351. y.onerror = function (z) {
  352. console.log(["delete.error", z]);
  353. };
  354.  
  355. xthis.delete.apply(xthis, [y]);
  356. }
  357. } else {
  358. x.onerror.apply(xthis, [x]);
  359. }
  360. }
  361. };
  362.  
  363. for (var i in p) {
  364. x[i] = p[i];
  365. }
  366.  
  367. return this.request(x);
  368. };
  369.  
  370. if (1 == Math.abs(obj.mode)) { // prepend or append
  371. var value = obj.value,
  372. onload = obj.onload,
  373. xthis = this;
  374.  
  375. obj.onload = function (x) {
  376. obj.onload = onload;
  377.  
  378. if (-1 == obj.mode) { // prepend
  379. obj.value = value + obj.value;
  380. } else { // append
  381. obj.value += value;
  382. }
  383.  
  384. return execute.apply(xthis, [obj]);
  385. };
  386.  
  387. return this.read.apply(this, [obj]);
  388. } else {
  389. return execute.apply(this, [obj]);
  390. }
  391. },
  392. read : function (obj) {
  393. if ("key" in obj) {
  394. var onload = obj.onload,
  395. xthis = this,
  396. p = {
  397. read : false,
  398. url : "http://pastebin.com/download.php",
  399. method : "get",
  400. adata : {
  401. i : obj.key
  402. },
  403. onload : function (x) {
  404. obj.onload = onload;
  405.  
  406. if (x.response.raw().finalUrl.indexOf(x.url)) {
  407. obj.value = "";
  408.  
  409. obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
  410. } else {
  411. obj.read = true;
  412.  
  413. obj.onload.apply(xthis, [obj]);
  414. }
  415. }
  416. };
  417. for (var i in p) {
  418. obj[i] = p[i];
  419. }
  420.  
  421. return this.request(obj);
  422. } else {
  423. obj.value = "";
  424. obj.read = false;
  425.  
  426. obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
  427. }
  428. },
  429. delete : function (obj) {
  430. var onload = obj.onload,
  431. value = obj.value,
  432. xthis = this,
  433. p = {
  434. url : "http://pastebin.com/api/api_post.php",
  435. method : "post",
  436. adata : JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
  437. // api_dev_key : "", // required
  438. // api_user_key : "",
  439. }))),
  440. pdata : {},
  441. odata : {
  442. api_paste_key : obj.key,
  443. api_option : "delete"
  444. },
  445. onload : function (x) {
  446. if (/^Paste Removed$/i.test(x.value)) {
  447. obj.onload = onload;
  448. obj.value = value;
  449.  
  450. obj.onload.apply(xthis, [obj]);
  451. } else {
  452. obj.onerror.apply(xthis, [obj]);
  453. }
  454. }
  455. };
  456.  
  457. for (var i in p) {
  458. obj[i] = p[i];
  459. }
  460.  
  461. return this.request(obj);
  462. },
  463. },
  464. PASTEBIN2 : {
  465. write : function (obj) {
  466. var ovalue = obj.value,
  467. xthis = this,
  468. execute = function (x) {
  469. var onload = x.onload,
  470. nvalue = x.value,
  471. p = {
  472. method : "post",
  473. adata : JSON.parse(GM_getValue("pastebin2_adata", JSON.stringify({
  474. // paste_private : "1",
  475. }))),
  476. pdata : {
  477. paste_format : "1",
  478. paste_private : "2",
  479. paste_expire_date : "N",
  480. paste_code : x.value, // required
  481. },
  482. odata : {
  483. submit : "Submit",
  484. submit_hidden : "submit_hidden",
  485. item_key : obj.key,
  486. post_key : obj.key,
  487. },
  488. onload : function (y) {
  489. var doc = y.response.doc(),
  490. url = y.response.raw().finalUrl;
  491.  
  492. if (/warning\.php\?p=(\d+)/i.test(url)) {
  493. x.code = RegExp.$1 - 1;
  494. x.value = [
  495. "You have reached your limit of [10] pastes per 24 hours.",
  496. "You have reached your limit of [20] pastes per 24 hours.",
  497. "You have reached your limit of [250] pastes per 24 hours.",
  498. ][x.code] || xpath("string(id('content_left')/div[2])", doc) || "Unknown error (WARN " + x.code + ")";
  499.  
  500. x.onerror.apply(xthis, [x]);
  501. } else if ((/^https?:/i.test(url)) && (/\/(\w+)$/.test(url))) {
  502. x.key = RegExp.$1;
  503.  
  504. if (xpath("string(.//text()[contains(., 'Pastebin.com is under heavy load right now')])", doc)) {
  505. x.onerror.apply(xthis, [x]);
  506. } else {
  507. if (xpath("id('siimage')", doc)[0]) {
  508. x.value = nvalue;
  509. GM_log(ovalue);
  510. alert("A new window will be opened. You must fill the captcha correctly, otherwise you will lose your data and a new paste will be created next time.");
  511. GM_openInTab(url);
  512. } else {
  513. var code = xpath("id('paste_code')", doc)[0];
  514. x.value = code && code.textContent || "";
  515. }
  516. x.onload = onload;
  517. x.onload.apply(xthis, [x]);
  518. }
  519. } else {
  520. x.value = [
  521. "You have exceeded the maximum file size of [500] kilobytes per paste.",
  522. "You cannot create an empty paste.",
  523. "You have reached the maximum number of [25] unlisted pastes.",
  524. "You have reached the maximum number of [10] private pastes.",
  525. ][/index\.php\?e=(\d+)/.test(url) && (x.code = RegExp.$1 - 1)] || xpath("string(id('notice'))", doc) || "Unknown error (ERROR " + x.code + ")";
  526.  
  527. x.onerror.apply(xthis, [x]);
  528. }
  529. }
  530. };
  531.  
  532. for (var i in p) {
  533. x[i] = p[i];
  534. }
  535.  
  536. return this.request(x);
  537. };
  538.  
  539. if (1 == Math.abs(obj.mode)) { // prepend or append
  540. var onload = obj.onload;
  541.  
  542. if ("" != ovalue) {
  543. obj.onload = function (x) {
  544. obj.onload = onload;
  545.  
  546. if (-1 == obj.mode) { // prepend
  547. obj.value = ovalue + obj.value;
  548. } else { // append
  549. obj.value += ovalue;
  550. }
  551.  
  552. return execute.apply(xthis, [obj]);
  553. };
  554. }
  555.  
  556. return xthis.read.apply(xthis, [obj]);
  557. } else {
  558. return execute.apply(xthis, [obj]);
  559. }
  560. },
  561. read : function (obj) {
  562. var xthis = this;
  563.  
  564. if ("key" in obj && obj.key) {
  565. var onload = obj.onload,
  566. p = {
  567. read : false,
  568. url : "http://pastebin.com/download.php",
  569. method : "get",
  570. adata : {
  571. i : obj.key
  572. },
  573. onload : function (x) {
  574. var url = x.response.raw().finalUrl;
  575.  
  576. x.onload = onload;
  577.  
  578. if (url.indexOf(x.url)) { // Unknown Paste ID
  579. x.value = "";
  580. x.url = "http://pastebin.com/post.php";
  581. x.key = "";
  582.  
  583. x[typeof x.onwarn == "function"?"onwarn":"onload"].apply(this, [x]);
  584. } else if (~x.value.indexOf("this is a private paste. If this is your private paste")) { // may occur false positive
  585. x.value = "This is a private paste (#"+x.key+"). You must login to Pastebin first.";
  586. x.onerror.apply(xthis, [x]);
  587. } else if (~x.value.indexOf("Pastebin.com is under heavy load right now")) {
  588. x.value = "Pastebin.com is under heavy load right now.";
  589. x.onerror.apply(xthis, [x]);
  590. } else {
  591. x.read = true;
  592. x.url = "http://pastebin.com/edit.php";
  593.  
  594. x.onload.apply(xthis, [x]);
  595. }
  596. }
  597. };
  598. for (var i in p) {
  599. obj[i] = p[i];
  600. }
  601.  
  602. return this.request(obj);
  603. } else {
  604. obj.read = false;
  605. obj.url = "http://pastebin.com/post.php";
  606. obj.key = "";
  607.  
  608. this.request({
  609. url : "http://pastebin.com/",
  610. method : "get",
  611. onload : function (c) {
  612. if (xpath("boolean(id('header_bottom')//a[contains(@href, '/logout')])", c.response.doc())) {
  613. obj.value = "";
  614.  
  615. obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(xthis, [obj]);
  616. } else {
  617. obj.value = "You must login to Pastebin first.";
  618.  
  619. obj.onerror.apply(xthis, [obj]);
  620. }
  621. },
  622. onerror : function (c) {
  623. c.value = xpath("string(id('content_left')/div[1])", c.response.doc());
  624.  
  625. obj.onerror(c);
  626. },
  627. });
  628. }
  629. },
  630. delete : function (obj) {
  631. var onload = obj.onload,
  632. value = obj.value,
  633. xthis = this,
  634. p = {
  635. url : "http://pastebin.com/delete.php",
  636. method : "get",
  637. adata : {},
  638. pdata : {},
  639. odata : {
  640. i : obj.key,
  641. r : "/" + obj.key
  642. },
  643. onload : function (x) {
  644. if (/^Paste Removed$/i.test(x.value)) {
  645. obj.onload = onload;
  646. obj.value = value;
  647.  
  648. obj.onload.apply(xthis, [obj]);
  649. } else {
  650. obj.onerror.apply(xthis, [obj]);
  651. }
  652. }
  653. };
  654.  
  655. for (var i in p) {
  656. obj[i] = p[i];
  657. }
  658.  
  659. return this.request(obj);
  660. }
  661. }
  662. };
  663.  
  664. Persist.write = function (obj) {
  665. var p = new Persist(obj.service);
  666.  
  667. return p.write.apply(p, [obj]);
  668. };
  669.  
  670. Persist.delete = function (obj) {
  671. var p = new Persist(obj.service);
  672.  
  673. return p.delete.apply(p, [obj]);
  674. };
  675.  
  676. Persist.read = function (obj) {
  677. var p = new Persist(obj.service);
  678.  
  679. return p.read.apply(p, [obj]);
  680. };