- // ==UserScript==
- // @name dmhy tree view
- // @namespace https://gf.qytechs.cn/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;
- }
- });
- });
- })();