dmhy tree view

convert plain file list into a tree view for 动漫花园 (share.dmhy.org)

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         dmhy tree view
// @namespace    https://greasyfork.org/zh-CN/scripts/26430-dmhy-tree-view
// @license      GPL version 3
// @encoding     utf-8
// @version      0.35
// @date         2017/01/11
// @modified     2020/12/20
// @description  convert plain file list into a tree view for 动漫花园 (share.dmhy.org)
// @author       TautCony
// @require      http://cdn.bootcss.com/jquery/3.5.1/jquery.min.js
// @require      http://cdn.bootcss.com/jstree/3.3.11/jstree.min.js
// @resource     customCSS http://cdn.bootcss.com/jstree/3.3.11/themes/default/style.min.css
// @match        *://share.dmhy.org/topics/view/*
// @match        *://dmhy.anoneko.com/topics/view/*
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @run-at       document-end
// ==/UserScript==
var iconOrigin = location.origin;
var icons = {
    audio: iconOrigin + "/images/icon/mp3.gif",
    bmp: iconOrigin + "/images/icon/bmp.gif",
    image: iconOrigin + "/images/icon/jpg.gif",
    png: iconOrigin + "/images/icon/png.gif",
    rar: iconOrigin + "/images/icon/rar.gif",
    text: iconOrigin + "/images/icon/txt.gif",
    unknown: iconOrigin + "/images/icon/unknown.gif",
    video: iconOrigin + "/images/icon/mp4.gif",
};
var type2Icon = {
    audio: ["flac", "aac", "wav", "mp3"],
    bmp: ["bmp"],
    image: ["jpg", "jpeg", "webp"],
    png: ["png"],
    rar: ["rar", "zip", "7z"],
    text: ["txt", "log", "cue", "ass"],
    video: ["mkv", "mka", "mp4"],
};
var Dictionary = /** @class */ (function () {
    function Dictionary() {
        this.data = {};
    }
    Dictionary.prototype.add = function (key, value) {
        if (!(key in this.data)) {
            this.data[key] = value;
        }
    };
    Dictionary.prototype.clear = function () {
        this.data = {};
    };
    Dictionary.prototype.containsKey = function (key) {
        return key in this.data;
    };
    Dictionary.prototype.get = function (key) {
        return this.data[key];
    };
    Dictionary.prototype.size = function () {
        return Object.keys(this.data).length;
    };
    Dictionary.prototype.values = function () {
        return this.data;
    };
    return Dictionary;
}());
var FileSize = /** @class */ (function () {
    function FileSize() {
    }
    FileSize.toLength = function (size) {
        if (size === undefined) {
            return -1;
        }
        var head = "";
        var tail = "";
        var isNumber = function (c) { return (c >= "0" && c <= "9") || c === "." || c === "-"; };
        for (var _i = 0, _a = size.toLowerCase(); _i < _a.length; _i++) {
            var c = _a[_i];
            if (isNumber(c)) {
                head += c;
            }
            else {
                tail += c;
            }
        }
        var value = parseFloat(head);
        switch (tail) {
            case "byte": return value * Math.pow(2, 0);
            case "bytes": return value * Math.pow(2, 0);
            case "kb": return value * Math.pow(2, 10);
            case "mb": return value * Math.pow(2, 20);
            case "gb": return value * Math.pow(2, 30);
            case "tb": return value * Math.pow(2, 40);
        }
        return -1;
    };
    FileSize.toSize = function (length) {
        if (length >= Math.pow(2, 40)) {
            return this.format(length, 40, "TiB");
        }
        else if (length >= Math.pow(2, 30)) {
            return this.format(length, 30, "GiB");
        }
        else if (length >= Math.pow(2, 20)) {
            return this.format(length, 20, "MiB");
        }
        else if (length >= Math.pow(2, 10)) {
            return this.format(length, 10, "KiB");
        }
        else {
            return this.format(length, 0, "Bytes", 0);
        }
    };
    FileSize.format = function (length, factor, tail, digits) {
        if (digits === undefined) {
            digits = 3;
        }
        return (length / Math.pow(2, factor)).toFixed(digits).toString() + tail;
    };
    return FileSize;
}());
var TreeNode = /** @class */ (function () {
    function TreeNode(node) {
        this._ext = undefined;
        this._icon = undefined;
        this.name = node;
        this.length = 0;
        this.childNode = new Dictionary();
    }
    TreeNode.prototype.insert = function (path, size) {
        var currentNode = this;
        for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
            var node = path_1[_i];
            var next = currentNode.childNode.get(node);
            if (!currentNode.childNode.containsKey(node)) {
                next = currentNode.add(node, new TreeNode(node));
                next.pareneNode = currentNode;
            }
            currentNode = next;
        }
        currentNode.length = FileSize.toLength(size);
        return currentNode;
    };
    TreeNode.prototype.toString = function () {
        return "<span class=\"filename\">" + this.name + "</span><span class=\"filesize\">" + FileSize.toSize(this.length) + "</span>";
    };
    TreeNode.prototype.toObject = function () {
        var ret = {
            children: [],
            length: 0,
            state: {
                opened: true,
            },
            text: this.toString(),
        };
        var childNodeValues = this.childNode.values();
        for (var key in childNodeValues) {
            if (!childNodeValues.hasOwnProperty(key)) {
                continue;
            }
            var files = [];
            var value = this.childNode.get(key);
            if (value.childNode.size() === 0) {
                files.push(value);
            }
            else {
                var inner = value.toObject();
                value.length = inner.length = inner.children.reduce(function (aac, val) { return aac + val.length; }, 0);
                inner.text = value.toString(); //update text with size info
                inner.state.opened = false;
                ret.children.push(inner);
            }
            for (var _i = 0, files_1 = files; _i < files_1.length; _i++) {
                var file = files_1[_i];
                ret.length += file.length;
                ret.children.push({
                    icon: file.icon,
                    length: file.length,
                    text: file.toString(),
                });
            }
        }
        return ret;
    };
    TreeNode.prototype.add = function (key, value) {
        this.childNode.add(key, value);
        return this.childNode.get(key);
    };
    Object.defineProperty(TreeNode.prototype, "ext", {
        get: function () {
            if (this._ext !== undefined) {
                return this._ext;
            }
            this._ext = "";
            var dotIndex = this.name.lastIndexOf(".");
            if (dotIndex > 0) {
                this._ext = this.name.substr(dotIndex + 1).toLowerCase();
            }
            return this._ext;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(TreeNode.prototype, "icon", {
        get: function () {
            if (this._icon !== undefined) {
                return this._icon;
            }
            this._icon = icons.unknown;
            for (var type in type2Icon) {
                if (type2Icon[type].indexOf(this.ext) >= 0) {
                    this._icon = icons[type];
                    break;
                }
            }
            return this._icon;
        },
        enumerable: false,
        configurable: true
    });
    return TreeNode;
}());
var GM_getResourceText = GM_getResourceText;
var GM_addStyle = GM_addStyle;
var copyToClipboard = function (text) {
    if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in MS Edge.
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy"); // Security exception may be thrown by some browsers.
        }
        catch (ex) {
            console.warn("Copy to clipboard failed.", ex);
            return false;
        }
        finally {
            document.body.removeChild(textarea);
        }
    }
};
var setupCSS = function () {
    if (typeof GM_getResourceText !== "undefined") {
        GM_addStyle(GM_getResourceText("customCSS"));
        $("head").append("<style>.jstree-node,.jstree-default .jstree-icon{background-image:url(http://cdn.bootcss.com/jstree/3.3.3/themes/default/32px.png);}.filesize{padding-left:1em;color:grey;}</style>");
        $(".file_list").css("width", "100%");
        $(".file_list").css("max-height", "600px");
    }
    else {
        console.info("%cTo load style sheet and let script works correctly, http://tampermonkey.net/ is required.", "color:#e55d67;font-size:1.3em");
    }
};
var setupOpe = function () {
    $("#tabs-1").append('<input type="text" style="width:240px;margin:0;padding:6px 12px;border-radius:4px;border:1px solid silver;font-size:1.1em;" id="search_input" placeholder="Search" />');
    $("#tabs-1").append('<button id="switch" style="border:0;border-radius:2px;padding:8px;margin-left:10px;">Expand All</button>');
    $("#tabs-1").append('<input id="hidden_text" style="display:none;"/>');
};
(function () {
    setupCSS();
    setupOpe();
    var data = new TreeNode($(".topic-title > h3").text());
    var pattern = /^(.+?) (\d+(?:\.\d+)?[TGMK]?B(?:ytes)?)$/;
    $(".file_list:first > ul li").each(function (index, value) {
        var text = $(value).text().trim();
        var line = text.replace(/\t+/i, "\t").split("\t");
        switch (line.length) {
            case 2:
                var nodes = line[0].split("/");
                var size = line[1];
                data.insert(nodes, size);
                break;
            case 1:
                var ret = pattern.exec(text);
                if (ret === null) {
                    //the text should be "More Than 1000 Files"
                    data.insert(line[0].split("/"), "");
                }
                else {
                    data.insert(ret[1].split("/"), ret[2]);
                }
                break;
            default:
                console.log("Unexpected length in \"" + line + "\"");
        }
    });
    var getSelectedRow = function (reference) { return $.jstree.reference(reference).get_node(reference, true); };
    var options = {
        contextmenu: {
            items: {
                getText: {
                    action: function (selected) { return copyToClipboard(selected.reference.find(".filename").text()); },
                    label: "Copy",
                },
                remove: {
                    action: function (selected) { return getSelectedRow(selected.reference).remove(); },
                    label: "Delete",
                },
            },
            show_at_node: false,
        },
        core: {
            data: data.toObject(),
        },
        plugins: ["search", "wholerow", "contextmenu"],
    };
    $($(".file_list:first").jstree(options)).bind("loaded.jstree", function (loadedEventData) {
        var isExpended = false;
        $("#switch").click(function (clickEventData) {
            if (isExpended) {
                clickEventData.target.innerHTML = "Expand All";
                $(loadedEventData.target).jstree("close_all");
            }
            else {
                clickEventData.target.innerHTML = "Toggle All";
                $(loadedEventData.target).jstree("open_all");
            }
            isExpended = !isExpended;
        });
        var lastVal = "";
        $("#search_input").keyup(function (keyupEventData) {
            var val = keyupEventData.target.value;
            if (val !== lastVal) {
                $(loadedEventData.target).jstree(true).search(val);
                lastVal = val;
            }
        });
    });
})();