Persist

Persist Function

目前为 2017-04-21 提交的版本。查看 最新版本

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