Persist

Persist Function

Detta skript bör inte installeras direkt. Det är ett bibliotek för andra skript att inkludera med meta-direktivet // @require https://update.greasyfork.org/scripts/29175/189868/Persist.js

// ==UserScript==
// @name           Persist
// @namespace      http://gm.wesley.eti.br
// @description    Persist Function
// @author         w35l3y
// @email          w35l3y@brasnet.org
// @copyright      2013+, w35l3y (http://gm.wesley.eti.br)
// @license        GNU GPL
// @homepage       http://gm.wesley.eti.br
// @version        1.0.1.0
// @language       en
// @include        nowhere
// @exclude        *
// @require        https://greasyfork.org/scripts/29175-xpath/code/XPath.js?version=189855
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @connect *
// ==/UserScript==

/**************************************************************************

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

**************************************************************************/

var Persist = function (s) {
    var service = Persist.services[s];

    this.request = function (obj) {
        var k,
            xthis = this,
            params = function (def) {
                var list = {};

                this.add = function (vars) {
                    if (vars) {

                        if (typeof vars == "object") {
                            for (var k in vars) {
                                var e = vars[k];

                                if (typeof e == "object" && (!/^(?:radio|checkbox)$/i.test(e.type) || e.checked)) {
                                    var n = e.name || k;

                                    if (e.checked && /^checkbox$/i.test(e.type)) {
                                        if (n in list) {
                                            list[n].push(e.value);
                                        } else {
                                            list[n] = [e.value];
                                        }
                                    } else if ("value" in e) {
                                        list[n] = e.value;
                                    } else {
                                        list[n] = e;
                                    }
                                } else {
                                    list[k] = e;
                                }
                            }
                        } else {
                            list = vars;
                        }
                    }
                };

                this.toString = function() {
                    if (typeof list == "object") {
                        var data = "";
                        for (var key in list) {
                            if (list[key] instanceof Array) {
                                var keyarr = key.replace(/^\s+|\s+$/g, "");
                                if (!/\[\w*\]$/.test(key)) keyarr += "[]";

                                for (var k in list[key]) {
                                    var v = list[key][k];
                                    data += "&" + encodeURIComponent(keyarr) + "=" + encodeURIComponent(v);
                                }
                            } else {
                                data += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(list[key]);
                            }
                        }

                        return data.substr(1);
                    } else {
                        return list;
                    }
                };
            },
            data = new params();

        data.add(obj.pdata);
        data.add(obj.adata);
        data.add(obj.data);
        data.add(obj.odata);

        if (typeof obj.onload != "function") {
            obj.onload = function (obj) {
                console.log(["request.load", obj]);
            };
        }

        if (typeof obj.onerror != "function") {
            obj.onerror = function (obj) {
                console.log(["request.error", obj]);
            };
        }

        var update = function (obj, e) {
            obj.response = {
                raw	: function () {return e;},
                text	: function () {return e.responseText;},
                json	: function () {
                    try {
                        return JSON.parse(e.responseText);
                    } catch (x) {
                        return eval("(" + e.responseText + ")");
                    }
                },
                doc	: function () {
                    try {
                        return new DOMParser().parseFromString(e.responseText, /^Content-Type: ([\w/]+)$/mi.test(e.responseHeaders) && RegExp.$1 || "text/html");
                    } catch (x) {
                        var doc = document.implementation.createHTMLDocument("");
                        doc.documentElement.innerHTML = e.responseText;

                        return doc;
                    }
                },
            };
            obj.value = e.responseText;
        },
            params = {
                url		: obj.url,
                method	: obj.method,
                onload	: function (e) {
                    update(obj, e);

                    obj[(/^2/.test(e.status)?"onload":"onerror")].apply(xthis, [obj]);
                },
                onerror	: function (e) {
                    update(obj, e);

                    obj.onerror.apply(xthis, [obj]);
                }
            },
            sdata = data.toString();

        if (/^post$/i.test(obj.method)) {
            var p = {
                headers	: {
                    "Content-Type"	: "application/x-www-form-urlencoded"
                },
                data	: sdata,
            };

            console.log(sdata);

            for (k in p) {
                params[k] = p[k];
            }
        } else if (sdata) {
            params.url += "?" + sdata;

        }

        if (typeof obj.headers == "object")
            for (k in obj.headers) {
                params.headers[k] = obj.headers[k];
            }

        return GM_xmlhttpRequest(params);
    };

    for (var k in service) {
        this[k] = service[k];
    }
};

Persist.services	= {
    LOCAL		: {
        write	: function (obj) {
            var label_keys = "persist_keys-" + obj.service,
                label_data = "persist_data-" + obj.service,
                mapping = JSON.parse(GM_getValue(label_keys, "{}")),
                data = JSON.parse(GM_getValue(label_data, "[]")),
                key = obj.key;

            if (key in mapping) {
                key = mapping[obj.key];
            }

            if (key in data) {
                var tv = typeof obj.value,
                    td = typeof data[key];

                if ((td != tv) && (td == "object" || tv == "object")) {
                    throw ["Incompatible types ", td, tv].toString();
                } else {
                    switch (td) {
                        case "string":
                            if (-1 == obj.mode) {	// prepend
                                data[key] = obj.value + data[key];
                            } else if (1 == obj.mode) {	// append
                                data[key] += obj.value;
                            } else {	// overwrite (default)
                                data[key] = obj.value;
                            }
                            break;
                        case "boolean":
                            if (-1 == obj.mode) {	// unused
                                throw ["Reserved action"].toString();
                            } else if (1 == obj.mode) {	// toggle
                                data[key] = !data[key];
                            } else {	// overwrite (default)
                                data[key] = !!value;
                            }
                            break;
                        case "number":
                            var value = Number(obj.value);

                            if (-1 == obj.mode) {	// subtract
                                data[key] -= value;
                            } else if (1 == obj.mode) {	// add
                                data[key] += value;
                            } else {	// overwrite (default)
                                data[key] = value;
                            }
                            break;
                        case "object":
                            if (-1 == obj.mode) {	// prepend
                                for (var k in data[key]) {
                                    obj.value[k] = data[key][k];
                                }
                                data[key] = obj.value;
                            } else if (1 == obj.mode) {	// append
                                for (var k in obj.value) {
                                    data[key][k] = obj.value[k];
                                }
                            } else {	// overwrite (default)
                                data[key] = obj.value;
                            }
                            break;
                        default:
                            throw ["Unsupported type " + td, data[key], key].toString();
                    }

                    obj.value = data[key];
                }
            } else {
                var tkey = data.push(obj.value);

                if (--tkey != key) {
                    if ("key" in obj) {
                        if (key in mapping) {
                            console.log(["Wrong mapping... ", tkey, key]);
                        }

                        mapping[key] = tkey;
                        obj.key = key;

                        GM_setValue(label_keys, JSON.stringify(mapping));
                    } else {
                        obj.key = tkey;
                    }
                }
            }

            GM_setValue(label_data, JSON.stringify(data));

            if (typeof obj.onload != "function") {
                obj.onload = function (obj) {
                    console.log(["write.load", obj]);
                };
            }

            return obj.onload.apply(this, [obj]);
        },
        delete	: function (obj) {
            throw ["Not implemented"].toString();
        },
        read	: function (obj) {
            var mapping = JSON.parse(GM_getValue("persist_keys-" + obj.service, "{}")),
                key = obj.key;

            if (key in mapping) {
                key = mapping[key];
            }

            obj.value = JSON.parse(GM_getValue("persist_data-" + obj.service, "[]"))[key];

            if (typeof obj.onload != "function") {
                obj.onload = function (obj) {
                    console.log(["read.load", obj]);
                };
            }

            return obj.onload.apply(this, [obj]);
        },
    },
    PASTEBIN	: {
        write	: function (obj) {
            var execute = function (x) {
                var onload = x.onload,
                    value = x.value,
                    xthis = this,
                    p = {
                        url		: "http://pastebin.com/api/api_post.php",
                        method	: "post",
                        adata		: JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
                            //						api_dev_key			: "",	// required
                            //						api_user_key		: "",
                        }))),
                        pdata		: {
                            api_paste_format		: "text",
                            api_paste_private		: "1",
                            api_paste_expire_date	: "N",
                            api_paste_code		: x.value,	// required
                        },
                        odata		: {
                            api_paste_key		: obj.key,
                            api_option			: "paste"
                        },
                        onload	: function (y) {
                            if (/^https?:\/\//i.test(y.value) && /\w+$/.test(y.value)) {
                                var key = x.key;
                                x.key = RegExp["$&"];

                                x.onload = onload;
                                x.value = value;

                                x.onload.apply(xthis, [x]);

                                if (x.read) {
                                    /* It is implemented that way because currently there isn't an EDIT option via API */
                                    y.key = key;
                                    y.onload = function (z) {
                                        console.log(["delete.load", z]);
                                    };
                                    y.onerror = function (z) {
                                        console.log(["delete.error", z]);
                                    };

                                    xthis.delete.apply(xthis, [y]);
                                }
                            } else {
                                x.onerror.apply(xthis, [x]);
                            }
                        }
                    };

                for (var i in p) {
                    x[i] = p[i];
                }

                return this.request(x);
            };

            if (1 == Math.abs(obj.mode)) {	// prepend or append
                var value = obj.value,
                    onload = obj.onload,
                    xthis = this;

                obj.onload = function (x) {
                    obj.onload = onload;

                    if (-1 == obj.mode) {	// prepend
                        obj.value = value + obj.value;
                    } else {	// append
                        obj.value += value;
                    }

                    return execute.apply(xthis, [obj]);
                };

                return this.read.apply(this, [obj]);
            } else {
                return execute.apply(this, [obj]);
            }
        },
        read	: function (obj) {
            if ("key" in obj) {
                var onload = obj.onload,
                    xthis = this,
                    p = {
                        read		: false,
                        url		: "http://pastebin.com/download.php",
                        method	: "get",
                        adata		: {
                            i	: obj.key
                        },
                        onload	: function (x) {
                            obj.onload = onload;

                            if (x.response.raw().finalUrl.indexOf(x.url)) {
                                obj.value = "";

                                obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
                            } else {
                                obj.read = true;

                                obj.onload.apply(xthis, [obj]);
                            }
                        }
                    };
                for (var i in p) {
                    obj[i] = p[i];
                }

                return this.request(obj);
            } else {
                obj.value = "";
                obj.read = false;

                obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
            }
        },
        delete	: function (obj) {
            var onload = obj.onload,
                value = obj.value,
                xthis = this,
                p = {
                    url		: "http://pastebin.com/api/api_post.php",
                    method	: "post",
                    adata		: JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
                        //					api_dev_key			: "",	// required
                        //					api_user_key		: "",
                    }))),
                    pdata		: {},
                    odata		: {
                        api_paste_key		: obj.key,
                        api_option			: "delete"
                    },
                    onload	: function (x) {
                        if (/^Paste Removed$/i.test(x.value)) {
                            obj.onload = onload;
                            obj.value = value;

                            obj.onload.apply(xthis, [obj]);
                        } else {
                            obj.onerror.apply(xthis, [obj]);
                        }
                    }
                };

            for (var i in p) {
                obj[i] = p[i];
            }

            return this.request(obj);
        },
    },
    PASTEBIN2	: {
        write	: function (obj) {
            var ovalue = obj.value,
                xthis = this,
                execute = function (x) {
                    var onload = x.onload,
                        nvalue = x.value,
                        p = {
                            method	: "post",
                            adata	: JSON.parse(GM_getValue("pastebin2_adata", JSON.stringify({
                                //						paste_private		: "1",
                            }))),
                            pdata	: {
                                paste_format		: "1",
                                paste_private		: "2",
                                paste_expire_date	: "N",
                                paste_code			: x.value,	// required
                            },
                            odata	: {
                                submit			: "Submit",
                                submit_hidden	: "submit_hidden",
                                item_key		: obj.key,
                                post_key		: obj.key,
                            },
                            onload	: function (y) {
                                var doc = y.response.doc(),
                                    url = y.response.raw().finalUrl;

                                if (/warning\.php\?p=(\d+)/i.test(url)) {
                                    x.code = RegExp.$1 - 1;
                                    x.value = [
                                        "You have reached your limit of [10] pastes per 24 hours.",
                                        "You have reached your limit of [20] pastes per 24 hours.",
                                        "You have reached your limit of [250] pastes per 24 hours.",
                                    ][x.code] || xpath("string(id('content_left')/div[2])", doc) || "Unknown error (WARN " + x.code + ")";

                                    x.onerror.apply(xthis, [x]);
                                } else if ((/^https?:/i.test(url)) && (/\/(\w+)$/.test(url))) {
                                    x.key = RegExp.$1;

                                    if (xpath("string(.//text()[contains(., 'Pastebin.com is under heavy load right now')])", doc)) {
                                        x.onerror.apply(xthis, [x]);
                                    } else {
                                        if (xpath("id('siimage')", doc)[0]) {
                                            x.value = nvalue;
                                            GM_log(ovalue);
                                            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.");
                                            GM_openInTab(url);
                                        } else {
                                            var code = xpath("id('paste_code')", doc)[0];
                                            x.value = code && code.textContent || "";
                                        }
                                        x.onload = onload;
                                        x.onload.apply(xthis, [x]);
                                    }
                                } else {
                                    x.value = [
                                        "You have exceeded the maximum file size of [500] kilobytes per paste.",
                                        "You cannot create an empty paste.",
                                        "You have reached the maximum number of [25] unlisted pastes.",
                                        "You have reached the maximum number of [10] private pastes.",
                                    ][/index\.php\?e=(\d+)/.test(url) && (x.code = RegExp.$1 - 1)] || xpath("string(id('notice'))", doc) || "Unknown error (ERROR " + x.code + ")";

                                    x.onerror.apply(xthis, [x]);
                                }
                            }
                        };

                    for (var i in p) {
                        x[i] = p[i];
                    }

                    return this.request(x);
                };

            if (1 == Math.abs(obj.mode)) {	// prepend or append
                var onload = obj.onload;

                if ("" != ovalue) {
                    obj.onload = function (x) {
                        obj.onload = onload;

                        if (-1 == obj.mode) {	// prepend
                            obj.value = ovalue + obj.value;
                        } else {	// append
                            obj.value += ovalue;
                        }

                        return execute.apply(xthis, [obj]);
                    };
                }

                return xthis.read.apply(xthis, [obj]);
            } else {
                return execute.apply(xthis, [obj]);
            }
        },
        read	: function (obj) {
            var xthis = this;

            if ("key" in obj && obj.key) {
                var onload = obj.onload,
                    p = {
                        read		: false,
                        url		: "http://pastebin.com/download.php",
                        method	: "get",
                        adata		: {
                            i	: obj.key
                        },
                        onload	: function (x) {
                            var url = x.response.raw().finalUrl;

                            x.onload = onload;

                            if (url.indexOf(x.url)) {	// Unknown Paste ID
                                x.value = "";
                                x.url = "http://pastebin.com/post.php";
                                x.key = "";

                                x[typeof x.onwarn == "function"?"onwarn":"onload"].apply(this, [x]);
                            } else if (~x.value.indexOf("this is a private paste. If this is your private paste")) {	// may occur false positive
                                x.value = "This is a private paste (#"+x.key+"). You must login to Pastebin first.";
                                x.onerror.apply(xthis, [x]);
                            } else if (~x.value.indexOf("Pastebin.com is under heavy load right now")) {
                                x.value = "Pastebin.com is under heavy load right now.";
                                x.onerror.apply(xthis, [x]);
                            } else {
                                x.read = true;
                                x.url = "http://pastebin.com/edit.php";

                                x.onload.apply(xthis, [x]);
                            }
                        }
                    };
                for (var i in p) {
                    obj[i] = p[i];
                }

                return this.request(obj);
            } else {
                obj.read = false;
                obj.url = "http://pastebin.com/post.php";
                obj.key = "";

                this.request({
                    url		: "http://pastebin.com/",
                    method	: "get",
                    onload	: function (c) {
                        if (xpath("boolean(id('header_bottom')//a[contains(@href, '/logout')])", c.response.doc())) {
                            obj.value = "";

                            obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(xthis, [obj]);
                        } else {
                            obj.value = "You must login to Pastebin first.";

                            obj.onerror.apply(xthis, [obj]);
                        }
                    },
                    onerror	: function (c) {
                        c.value = xpath("string(id('content_left')/div[1])", c.response.doc());

                        obj.onerror(c);
                    },
                });
            }
        },
        delete	: function (obj) {
            var onload = obj.onload,
                value = obj.value,
                xthis = this,
                p = {
                    url		: "http://pastebin.com/delete.php",
                    method	: "get",
                    adata	: {},
                    pdata	: {},
                    odata	: {
                        i	: obj.key,
                        r	: "/" + obj.key
                    },
                    onload	: function (x) {
                        if (/^Paste Removed$/i.test(x.value)) {
                            obj.onload = onload;
                            obj.value = value;

                            obj.onload.apply(xthis, [obj]);
                        } else {
                            obj.onerror.apply(xthis, [obj]);
                        }
                    }
                };

            for (var i in p) {
                obj[i] = p[i];
            }

            return this.request(obj);
        }
    }
};

Persist.write = function (obj) {
    var p = new Persist(obj.service);

    return p.write.apply(p, [obj]);
};

Persist.delete = function (obj) {
    var p = new Persist(obj.service);

    return p.delete.apply(p, [obj]);
};

Persist.read = function (obj) {
    var p = new Persist(obj.service);

    return p.read.apply(p, [obj]);
};