// ==UserScript==
// @name DMHY download helper
// @name:zh-CN 动漫花园下载助手
// @description A userscript for share.dmhy.org.
// @description:zh-CN 动漫花园(share.dmhy.org)扩展,提供批量选择、列表下载种子文件及详情页树状展示等功能。
// @author Xingwang Liao
// @namespace https://github.com/kuoruan
// @homepage https://github.com/kuoruan/dmhy-download-helper#readme
// @supportURL https://github.com/kuoruan/dmhy-download-helper/issues
// @match *://dmhy.org/
// @match *://dmhy.org/topics/list/*
// @match *://dmhy.org/topics/list?*
// @match *://dmhy.org/topics/view/*
// @match *://www.dmhy.org/
// @match *://www.dmhy.org/topics/list/*
// @match *://www.dmhy.org/topics/list?*
// @match *://www.dmhy.org/topics/view/*
// @match *://share.dmhy.org/
// @match *://share.dmhy.org/topics/list/*
// @match *://share.dmhy.org/topics/list?*
// @match *://share.dmhy.org/topics/view/*
// @match *://dmhy.b168.net/
// @match *://dmhy.b168.net/topics/list/*
// @match *://dmhy.b168.net/topics/list?*
// @match *://dmhy.b168.net/topics/view/*
// @require https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.min.js
// @require https://cdn.jsdelivr.net/npm/xbytes@1.9.1/dist/index.min.js
// @connect dmhy.org
// @connect b168.net
// @grant GM_addStyle
// @grant GM_setClipboard
// @grant GM_xmlhttpRequest
// @source https://github.com/kuoruan/dmhy-download-helper.git
// @license MIT
// @run-at document-end
// @version 1.6.2
// @icon https://share.dmhy.org/favicon.ico
// ==/UserScript==
(function() {
"use strict";
GM_addStyle('body{position:relative}#topic_list .odd:hover,#topic_list .even:hover,#topic_list .odd:hover td,#topic_list .even:hover td{background-color:#0eb9e7}.toast[data-v-e92e135b]{position:fixed;bottom:30px;left:50%;z-index:99;display:none;padding:10px 20px;border-radius:2px;background-color:#333;transform:translate(-50%)}.toast.show[data-v-e92e135b]{display:block;animation:fadein-e92e135b .5s,fadeout-e92e135b .5s 2.5s}.toast .text[data-v-e92e135b]{color:#fff;font-size:14px;line-height:1.5}@-moz-keyframes fadein-e92e135b{0%{bottom:0;opacity:0}to{bottom:30px;opacity:1}}@-webkit-keyframes fadein-e92e135b{0%{bottom:0;opacity:0}to{bottom:30px;opacity:1}}@-o-keyframes fadein-e92e135b{0%{bottom:0;opacity:0}to{bottom:30px;opacity:1}}@keyframes fadein-e92e135b{0%{bottom:0;opacity:0}to{bottom:30px;opacity:1}}@-moz-keyframes fadeout-e92e135b{0%{bottom:30px;opacity:1}to{bottom:0;opacity:0}}@-webkit-keyframes fadeout-e92e135b{0%{bottom:30px;opacity:1}to{bottom:0;opacity:0}}@-o-keyframes fadeout-e92e135b{0%{bottom:30px;opacity:1}to{bottom:0;opacity:0}}@keyframes fadeout-e92e135b{0%{bottom:30px;opacity:1}to{bottom:0;opacity:0}}.select-all[data-v-2f21319e],.select[data-v-6070ffc2]{cursor:pointer;width:14px;height:14px}.overlay[data-v-99f90792]{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#0000004d;text-align:center}.overlay[data-v-99f90792]:after{display:inline-block;width:0;height:100%;content:"";vertical-align:middle}.overlay .popup[data-v-99f90792]{display:inline-block;overflow:hidden;padding:2px;border:1px solid #247;background-color:#fff;box-shadow:0 2px 12px #0000001a;text-align:left;backface-visibility:hidden}.overlay .popup.middle[data-v-99f90792]{vertical-align:middle}.btn[data-v-272d8422]{padding:2px 5px;outline:none;border:1px solid #247;background-color:#fff;color:#247}.popup-header[data-v-272d8422]{display:flex;flex-direction:row;align-items:center;padding:5px;background-color:#247}.popup-header h4[data-v-272d8422]{flex:1 1 0;color:#fff;text-align:left;font-weight:400;font-size:14px;line-height:1.5}.popup-body[data-v-272d8422]{padding:5px;background-color:#fff}.popup-body .links-box[data-v-272d8422]{overflow:auto;padding:4px 8px;border:1px solid #247;background-color:#eef;background-image:none;color:#333;font-size:12px;line-height:1.5;resize:none;cursor:text}.popup-footer[data-v-272d8422]{display:flex;flex-direction:row;align-items:center;padding:5px;background-color:#cdf}.popup-footer .btn[data-v-272d8422]:not(:first-child){margin-left:10px}.popup-footer p[data-v-272d8422]{flex:1 1 0;margin:0;text-align:right}.tool-bar[data-v-0aeef348]{display:none;background-color:#247;color:#fff}.tool-bar.top[data-v-0aeef348]{border-bottom:1px solid #fff}.tool-bar.bottom[data-v-0aeef348]{border-top:1px solid #fff}.tool-bar.visible[data-v-0aeef348]{display:block}.wrapper[data-v-0aeef348]{display:flex;flex-direction:row;align-items:center;height:auto}.wrapper label[data-v-0aeef348]{margin-left:10px}.wrapper .title[data-v-0aeef348]{padding:8px 15px;border-right:2px solid #fff}.wrapper .checkbox[data-v-0aeef348]{width:14px;height:14px;vertical-align:middle}.wrapper .btn-wrapper[data-v-0aeef348]{margin-left:10px}.wrapper .btn-wrapper .btn[data-v-0aeef348]{margin:0 5px;padding:2px 5px;outline:none;border:1px solid #247;background-color:#fff;color:#247}.loading[data-v-f5ce47f3]{display:inline-block;border:2px solid #dbdfe4;border-radius:50%;border-top:2px solid #075ea4;width:12px;height:12px;animation:spinner-f5ce47f3 2s linear infinite}@-moz-keyframes spinner-f5ce47f3{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@-webkit-keyframes spinner-f5ce47f3{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@-o-keyframes spinner-f5ce47f3{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spinner-f5ce47f3{0%{transform:rotate(0)}to{transform:rotate(360deg)}}li.tree-item[data-v-3ab763b5]{margin:0;padding:2px 0 2px 16px;background:url(data:image/gif;base64,R0lGODlhEADwBvABAICAgAAAACH5BAUAAAEALAAAAAAQAPAGQAL/jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpfMpvMJjUqn1Kr1is1qt9yu9wsOi8fksvmMTqvX7Lb7DY/L5/S6/Y7P6/f8vv8PGCg4SFhoeIiYqLjI2Oj4CBkpOUlZaXmJmam5ydnp+QkaKjpKWmp6ipqqusp6ATDxKhEbMQvxehuAq1D7wOvg2wDMILxAvAuLLJtMu2zb3Pv8Gx08PVxdfH2svM3M7ewNDS4tTk1ubY6Nrt3N/t0e/j4eXz5/Xp9+v+6+D88v708PoD2B+Ajq64fwX8KACwc2LPjwoMKJDL0YS3ARQcYD/xsNdMyVDWNIjSM5lvR4EqQ6kStJtjT5EmVMlflY1nR5E2ZOmTtpGrT5E2dQnUN5FvUZEWhSoUuJNjX6FClFh1MhVpVYMStVrVa5Yt0KtmvYr2LLkj2r9Gpar2vHtjX7Fi1TtXPZ1nV7F25euU7p9rX7F29gvYP5QvV7GHBiwYsJNzYsVXFkxpMdV4b8MXNKzTM59/R8FHRU0Ygvxz29F3Vh1Y9Zm04Ne3Xs1rNfy75NG7ft3Lx3+yYtGThl4ZaJY96MvHPyz8tDNx/9vLRx19NrV9d9vXf239GDdx/+vXj448rLMzfvHD109dLHU3dvHT52+drpc2fvHT94/eL5k/8/D2B6Aa43YHv+vXdgfAnOt2B9Dd5XYH4R7jdhfxX+J2CGBGpo4IUIeqggiAyK6CCJEHIoIYoUqmghixhuCGOHLn44Y4g1jnhjiTmeGGOKPa74Y4tBvijjkDQaaSOSOCqpI5M8Fgmlj1ECOaWQVRIpZZZUamkll1huCWaXYX4pZplknnnklWl6ueaYbZr5JppJqjknm3W6eSececq5JJ192vknnoHqOSifTfp5KKCJCroooY0a+qSikTI6qaOVQrpdpvZp+iCnJnq6I6hOioropXGeuieqhar6KKumpgrrqrG2Ouurst5KK6625srrrr6SKimwlAprKbGYbopsp8knfrpsqM2O+mypxro6ba3V6nptr9n+Gm2w3Q77bbHhHqtsuczicksBADs=) 0 0 no-repeat}li.tree-item.collection[data-v-3ab763b5]{background-position:0 -176px}li.tree-item.last[data-v-3ab763b5]{background-position:0 -1766px}li.tree-item .hitarea[data-v-3ab763b5]{float:left;margin-left:-16px;width:16px;height:16px;background:url(data:image/gif;base64,R0lGODlhYACFAPACAAAAAICAgCH5BAUAAAIALAAAAABgAIUAAAL/lI+py+0PBZjA0Yiz3qjyD4aaJ5amSZ7qyrbuGsSy/NZmsOD2/unS4eMJIz5ScIhk4CgTAe6ZjCKKQKl1ejBet0dDdzucicHkstl5Tqul37X7fWrDUfNkqlqPXCzNPOjOIeeXNVhoeAgmNoNY8iXICOEIGSI52SPBhAZliVHJqeH52ZkjCqoYU5pq9aja+sLqGqsCqwoo+2BLW7fXwOtqCyoKfEtcbFx3inqMl6BbSuW1zKwljcZUAeU8CY1Wza39GXqcDF5tfo6ero4xXN3OmdnbF/u+nGtef3y/zu+UbC7O2DeAhKJ5w3Qh27iC3aQNPKignCVy/SpavCgtnzGNWsU4IvK1AGStih5vlcSIMhZFiM0IRnTZ8uA1TQ2JBSx20yYpb/9S+vwJdNBJeiSJiewwL6griUohMW06aKXDnVNfssQiM5NCgVSX5bz1VZZUqGTLmj2LNu2tAgA7) -48px -47px no-repeat;cursor:pointer}li.tree-item .hitarea.last-hitarea[data-v-3ab763b5]{background-color:#fff;background-position:-32px -69px}li.tree-item .hitarea.collapsable-hitarea[data-v-3ab763b5]{background-position:-16px -91px}li.tree-item .hitarea.collapsable-hitarea.last-hitarea[data-v-3ab763b5]{background-position:0 -113px}li.tree-item .title[data-v-3ab763b5]{position:relative;display:flex;flex-direction:row;box-sizing:border-box;padding-left:18px;width:100%;height:16px;line-height:16px}li.tree-item .title h5[data-v-3ab763b5]{flex:1 1 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;font-size:12px}li.tree-item .title[data-v-3ab763b5]:before{position:absolute;top:0;left:0;display:block;width:16px;height:16px;background-color:#fff;background-repeat:no-repeat;content:""}li.tree-item .title.folder-close[data-v-3ab763b5]:before{background-image:url(data:image/gif;base64,R0lGODdhEAAOAPIHAK1zLeC6eP/insOHNP/////Sg59oJJdaHywAAAAAEAAOAEADM0i63AoiygnYkCWEwXkzYCg6RDeQyzWtB3MUcCy3aL1Ud33qDLRSDINsWDC4AMQYzUZKAAA7)}li.tree-item .title.folder-open[data-v-3ab763b5]:before{background-image:url(data:image/gif;base64,R0lGODlhEAAOAIIAAZdaH+C6eP/inq1zLf/////Sg59oJMOHNCwAAAAAEAAOAAIDN0i63P7vyAPXYBcewUsIk8RQFalsXKoCmDq8cEwMKa2mxWUUOe//GUDvB1wABsQiw8BsOitQQgIAOw==)}li.tree-item .title.document[data-v-3ab763b5]:before{background-image:url(data:image/gif;base64,R0lGODdhDwAOAPIHANS9fIy3oamMQX98XzmJdP////9tcGpsYiwAAAAADwAOAEADOlgl3KxQjWJMGefIKGi1UAdNUUQqYgQAKVoE8KQtZgHAAUFsYWm3rtKKxfH1jsbWybdclpqDqHSqSAAAOw==)}li.tree-item .title.video[data-v-3ab763b5]:before{background-image:url(/images/icon/mkv.gif)}li.tree-item .title.audio[data-v-3ab763b5]:before{background-image:url(/images/icon/mp3.gif)}li.tree-item .title.image[data-v-3ab763b5]:before{background-image:url(/images/icon/jpg.gif)}li.tree-item .title.archive[data-v-3ab763b5]:before{background-image:url(/images/icon/rar.gif)}li.tree-item .title.subtitle[data-v-3ab763b5]:before{background-image:url(/images/icon/txt.gif)}li.tree-item .title.unknown[data-v-3ab763b5]:before{background-image:url(/images/icon/unknown.gif)}li.tree-item .title .size[data-v-3ab763b5]{display:block;flex:0;color:gray;white-space:nowrap}li.tree-item:nth-child(2n)>.title[data-v-3ab763b5]{background-color:#cdf}li.tree-item::nth-child(odd)>.title[data-v-3ab763b5]{background-color:#fff}li.tree-item ul[data-v-3ab763b5]{margin:4px 0 0;padding:0;list-style:none}');
})();
(function(Vue2, XBytes) {
"use strict";
var render$9 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("div", { staticClass: "toast", class: { "show": _vm.show } }, [_c("span", { staticClass: "text" }, [_vm._v(_vm._s(_vm.text))])]);
};
var staticRenderFns$9 = [];
function normalizeComponent(scriptExports, render2, staticRenderFns2, functionalTemplate, injectStyles, scopeId, moduleIdentifier, shadowMode) {
var options = typeof scriptExports === "function" ? scriptExports.options : scriptExports;
if (render2) {
options.render = render2;
options.staticRenderFns = staticRenderFns2;
options._compiled = true;
}
if (scopeId) {
options._scopeId = "data-v-" + scopeId;
}
return {
exports: scriptExports,
options
};
}
const _sfc_main$9 = {
name: "ToastItem",
data() {
return {
text: "",
show: false,
timer: 0
};
},
methods: {
display(text) {
if (this.timer) {
window.clearTimeout(this.timer);
this.timer = 0;
}
this.text = text;
this.show = true;
const _self = this;
this.timer = window.setTimeout(function() {
_self.show = false;
_self.text = "";
_self.timer = 0;
}, 3e3);
}
}
};
var __component__$9 = /* @__PURE__ */ normalizeComponent(
_sfc_main$9,
render$9,
staticRenderFns$9,
false,
null,
"e92e135b"
);
const ToastItem = __component__$9.exports;
var render$8 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("th", { staticClass: "{sorter: false}", attrs: { "width": "40" } }, [_c("input", { directives: [{ name: "model", rawName: "v-model", value: _vm.checked, expression: "checked" }], staticClass: "select-all", attrs: { "type": "checkbox" }, domProps: { "checked": Array.isArray(_vm.checked) ? _vm._i(_vm.checked, null) > -1 : _vm.checked }, on: { "change": [function($event) {
var $$a = _vm.checked, $$el = $event.target, $$c = $$el.checked ? true : false;
if (Array.isArray($$a)) {
var $$v = null, $$i = _vm._i($$a, $$v);
if ($$el.checked) {
$$i < 0 && (_vm.checked = $$a.concat([$$v]));
} else {
$$i > -1 && (_vm.checked = $$a.slice(0, $$i).concat($$a.slice($$i + 1)));
}
} else {
_vm.checked = $$c;
}
}, function($event) {
return _vm.$emit("change", $event.target.checked);
}] } })]);
};
var staticRenderFns$8 = [];
const _sfc_main$8 = {
name: "CheckboxHeader",
data() {
return {
checked: false
};
}
};
var __component__$8 = /* @__PURE__ */ normalizeComponent(
_sfc_main$8,
render$8,
staticRenderFns$8,
false,
null,
"2f21319e"
);
const CheckboxHeader = __component__$8.exports;
var render$7 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("td", { attrs: { "width": "40" } }, [_c("input", { directives: [{ name: "model", rawName: "v-model", value: _vm.checked, expression: "checked" }], staticClass: "select", attrs: { "type": "checkbox", "data-index": _vm.index }, domProps: { "checked": Array.isArray(_vm.checked) ? _vm._i(_vm.checked, null) > -1 : _vm.checked }, on: { "change": [function($event) {
var $$a = _vm.checked, $$el = $event.target, $$c = $$el.checked ? true : false;
if (Array.isArray($$a)) {
var $$v = null, $$i = _vm._i($$a, $$v);
if ($$el.checked) {
$$i < 0 && (_vm.checked = $$a.concat([$$v]));
} else {
$$i > -1 && (_vm.checked = $$a.slice(0, $$i).concat($$a.slice($$i + 1)));
}
} else {
_vm.checked = $$c;
}
}, function($event) {
return _vm.$emit("change", $event.target.checked);
}] } })]);
};
var staticRenderFns$7 = [];
const _sfc_main$7 = {
name: "CheckboxItem",
props: {
index: {
type: Number,
default: 0
},
magnet: {
type: String,
default: ""
}
},
data() {
return {
checked: false
};
}
};
var __component__$7 = /* @__PURE__ */ normalizeComponent(
_sfc_main$7,
render$7,
staticRenderFns$7,
false,
null,
"6070ffc2"
);
const CheckboxItem = __component__$7.exports;
var render$6 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("div", { staticClass: "overlay", style: { "z-index": _vm.zIndex }, on: { "click": function($event) {
if ($event.target !== $event.currentTarget)
return null;
return _vm.$emit("overlay-click");
}, "touchmove": _vm.onScroll, "mousewheel": _vm.onScroll } }, [_c("div", { staticClass: "popup", class: { "middle": _vm.middle }, style: { "margin-top": `${_vm.marginTop}px` } }, [_vm._t("default")], 2)]);
};
var staticRenderFns$6 = [];
const _sfc_main$6 = {
name: "PopupWrapper",
props: {
zIndex: {
type: Number,
default: 10
},
middle: {
type: Boolean,
default: false
},
marginTop: {
type: Number,
default: 0
}
},
methods: {
onScroll(evt) {
const el = evt.target;
const { overflow, overflowY, overflowX } = window.getComputedStyle(el);
const { scrollTop, scrollHeight, clientHeight } = el;
const isAutoOrScroll = /(auto|scroll)/.test(
overflow + overflowX + overflowY
);
const scroll = scrollTop === 0 && evt.deltaY < 0 || Math.abs(scrollTop - (scrollHeight - clientHeight)) <= 1 && evt.deltaY > 0;
if (!isAutoOrScroll || scroll) {
evt.preventDefault();
}
}
}
};
var __component__$6 = /* @__PURE__ */ normalizeComponent(
_sfc_main$6,
render$6,
staticRenderFns$6,
false,
null,
"99f90792"
);
const PopupWrapper = __component__$6.exports;
function magnetLinksWithOptions(magnetLinks, opts) {
if (!magnetLinks || magnetLinks.length <= 0) {
return [];
}
if (opts.clean) {
return magnetLinks.map((l) => l.substring(0, l.indexOf("&")));
}
return [...magnetLinks];
}
function getDefaultLinebreak() {
let linebreak = "\n";
if (navigator.userAgent.indexOf("Windows") > -1) {
linebreak = "\r\n";
}
return linebreak;
}
function hashCode(str) {
let hash = 0;
if (!str || str.length <= 0)
return hash;
for (let i = 0, len = str.length; i < len; i++) {
let chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0;
}
return hash;
}
const TORRENT_LINK_TAG_REGEX = /<a(?:.+)href=["']((?:https?:)?\/\/[^"']+\.torrent)["'](?:.*)>(.+)?<\/a>/;
function getTorrentLinkFromHTML(html) {
const matches = html.match(TORRENT_LINK_TAG_REGEX);
if (matches && matches.length === 3) {
return { href: matches[1].replace(/\n/g, ""), title: matches[2] };
}
return null;
}
var render$5 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("popup-wrapper", { attrs: { "z-index": _vm.zIndex, "middle": false, "margin-top": 100 }, on: { "overlay-click": function($event) {
return _vm.$emit("close");
} } }, [_c("div", { staticClass: "popup-header" }, [_c("h4", [_vm._v("查看链接")]), _c("button", { staticClass: "btn", on: { "click": function($event) {
return _vm.$emit("close");
} } }, [_vm._v("关闭")])]), _c("div", { staticClass: "popup-body" }, [_c("textarea", { directives: [{ name: "model", rawName: "v-model", value: _vm.content, expression: "content" }], ref: "textarea", staticClass: "links-box", style: _vm.textStyle, attrs: { "rows": "10", "cols": "80" }, domProps: { "value": _vm.content }, on: { "input": function($event) {
if ($event.target.composing)
return;
_vm.content = $event.target.value;
} } })]), _c("div", { staticClass: "popup-footer" }, [_c("button", { staticClass: "btn", on: { "click": _vm.resetContent } }, [_vm._v("重置")]), _c("button", { staticClass: "btn", on: { "click": _vm.selectAll } }, [_vm._v("全选")]), _c("button", { staticClass: "btn", on: { "click": _vm.copySelected } }, [_vm._v("复制选中")]), _c("button", { staticClass: "btn", on: { "click": _vm.copyAll } }, [_vm._v("复制全部")]), _c("p", [_vm._v("共 " + _vm._s(_vm.links.length) + " 条链接")])])]);
};
var staticRenderFns$5 = [];
const _sfc_main$5 = {
name: "LinksPopup",
components: {
PopupWrapper
},
props: {
zIndex: {
type: Number,
default: 10
},
links: {
type: Array,
default() {
return [];
}
},
options: {
type: Object,
default() {
const linebreak = getDefaultLinebreak();
return {
separator: linebreak
};
}
}
},
data() {
return {
content: ""
};
},
computed: {
textStyle() {
if (["\n", "\r\n"].indexOf(this.options.separator) > -1 && this.links.length > 1) {
return {
"white-space": "nowrap",
"word-break": "normal"
};
} else {
return {
"white-space": "pre-line",
"word-break": "break-all"
};
}
}
},
watch: {
links() {
this.resetContent();
}
},
created() {
this.resetContent();
},
methods: {
resetContent() {
this.content = this.links.join(this.options.separator);
},
copySelected() {
const target = this.$refs["textarea"];
if (target) {
const start = target.selectionStart;
const finish = target.selectionEnd;
if (start < 0 || finish <= start) {
this.$toast.display("所选内容为空!");
return;
}
try {
const text = this.content.substring(start, finish);
GM_setClipboard(text, "{ type: 'text', mimetype: 'text/plain'}");
this.$toast.display("复制成功!");
} catch (e) {
this.$toast.display("复制失败。");
}
} else {
this.$toast.display("获取文本框失败!");
}
},
copyAll() {
if (!this.content) {
this.$toast.display("文本框内容为空!");
return;
}
try {
GM_setClipboard(
this.content,
"{ type: 'text', mimetype: 'text/plain'}"
);
this.$toast.display("复制成功!");
} catch (e) {
this.$toast.display("复制失败。");
}
},
selectAll() {
const target = this.$refs["textarea"];
if (target) {
target.select();
} else {
this.$toast.display("获取文本框失败!");
}
}
}
};
var __component__$5 = /* @__PURE__ */ normalizeComponent(
_sfc_main$5,
render$5,
staticRenderFns$5,
false,
null,
"272d8422"
);
const LinksPopup = __component__$5.exports;
var render$4 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("div", { staticClass: "tool-bar", class: [_vm.position, { "visible": _vm.visible }] }, [_c("div", { staticClass: "wrapper" }, [_c("span", { staticClass: "title" }, [_vm._v("下载助手")]), _c("label", { attrs: { "for": `clean-${_vm.position}` } }, [_vm._v("清理链接:")]), _c("input", { directives: [{ name: "model", rawName: "v-model", value: _vm.opts.clean, expression: "opts.clean" }], staticClass: "checkbox", attrs: { "id": `clean-${_vm.position}`, "type": "checkbox" }, domProps: { "checked": Array.isArray(_vm.opts.clean) ? _vm._i(_vm.opts.clean, null) > -1 : _vm.opts.clean }, on: { "change": function($event) {
var $$a = _vm.opts.clean, $$el = $event.target, $$c = $$el.checked ? true : false;
if (Array.isArray($$a)) {
var $$v = null, $$i = _vm._i($$a, $$v);
if ($$el.checked) {
$$i < 0 && _vm.$set(_vm.opts, "clean", $$a.concat([$$v]));
} else {
$$i > -1 && _vm.$set(_vm.opts, "clean", $$a.slice(0, $$i).concat($$a.slice($$i + 1)));
}
} else {
_vm.$set(_vm.opts, "clean", $$c);
}
} } }), _c("label", { attrs: { "for": `separator-${_vm.position}` } }, [_vm._v("分隔符:")]), _c("select", { directives: [{ name: "model", rawName: "v-model", value: _vm.opts.separator, expression: "opts.separator" }], attrs: { "id": `separator-${_vm.position}` }, on: { "change": function($event) {
var $$selectedVal = Array.prototype.filter.call($event.target.options, function(o) {
return o.selected;
}).map(function(o) {
var val = "_value" in o ? o._value : o.value;
return val;
});
_vm.$set(_vm.opts, "separator", $event.target.multiple ? $$selectedVal : $$selectedVal[0]);
} } }, [_c("option", { attrs: { "value": "\n" } }, [_vm._v("\\n")]), _c("option", { attrs: { "value": "\r\n" } }, [_vm._v("\\r\\n")]), _c("option", { attrs: { "value": " " } }, [_vm._v("\\t")]), _c("option", { attrs: { "value": " " } }, [_vm._v("空格")]), _c("option", { attrs: { "value": "," } }, [_vm._v(",")])]), _c("div", { staticClass: "btn-wrapper" }, [_c("button", { staticClass: "btn", on: { "click": function($event) {
return _vm.$emit("copy", _vm.opts);
} } }, [_vm._v("复制")]), _c("button", { staticClass: "btn", on: { "click": function($event) {
return _vm.$emit("show", _vm.opts);
} } }, [_vm._v("查看")])])])]);
};
var staticRenderFns$4 = [];
const _sfc_main$4 = {
name: "ToolBar",
props: {
position: {
type: String,
default: "top"
}
},
data() {
let linebreak = getDefaultLinebreak();
return {
visible: false,
opts: {
clean: true,
separator: linebreak
}
};
}
};
var __component__$4 = /* @__PURE__ */ normalizeComponent(
_sfc_main$4,
render$4,
staticRenderFns$4,
false,
null,
"0aeef348"
);
const ToolBar = __component__$4.exports;
var render$3 = function render2() {
var _vm = this;
_vm._self._c;
return _vm._m(0);
};
var staticRenderFns$3 = [function() {
var _vm = this, _c = _vm._self._c;
return _c("th", { staticClass: "{sorter: false}", attrs: { "width": "5%", "nowrap": "nowrap" } }, [_c("span", { staticClass: "title" }, [_vm._v("Torrent")])]);
}];
const _sfc_main$3 = {
name: "TorrentDownloadHeader"
};
var __component__$3 = /* @__PURE__ */ normalizeComponent(
_sfc_main$3,
render$3,
staticRenderFns$3,
false,
null,
null
);
const TorrentDownloadHeader = __component__$3.exports;
var render$2 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("td", { attrs: { "nowrap": "nowrap", "align": "center" } }, [_vm.loading ? _c("span", { staticClass: "loading" }) : _c("a", { staticClass: "download-arrow arrow-torrent", attrs: { "title": "Torrent 下载", "href": "javascript:void(0);", "data-index": _vm.index }, on: { "click": _vm.getAndDownloadTorrent } })]);
};
var staticRenderFns$2 = [];
const _sfc_main$2 = {
name: "TorrentDownloadItem",
props: {
index: {
type: Number,
default: 0
},
detailLink: {
type: String,
default: ""
},
title: {
type: String,
default: ""
}
},
data() {
return {
loading: false
};
},
methods: {
getTorrentUrl(pageLink, pageTitle) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: pageLink,
timeout: 15e3,
context: { pageTitle },
ontimeout: () => {
reject(new Error("下载超时,请重试!"));
},
onerror: () => {
reject(new Error("下载失败,请重试!"));
},
onload: ({ context = {}, responseText = "" }) => {
let torrent;
if (responseText && (torrent = getTorrentLinkFromHTML(responseText))) {
let url = torrent.href;
if (url.indexOf("//") === 0) {
url = window.location.protocol + url;
}
resolve({
url,
filename: `${torrent.title || context.pageTitle}.torrent`
});
} else {
reject(new Error("获取下载链接失败!"));
}
}
});
});
},
async downloadTorrent(torrentUrl, torrentName) {
const blob = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: torrentUrl,
responseType: "blob",
timeout: 15e3,
ontimeout: () => {
reject(new Error("下载超时,请重试!"));
},
onerror: () => {
reject(new Error("下载失败,请重试!"));
},
onload: ({ response }) => {
resolve(response);
}
});
});
const herf = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.href = herf;
anchor.style.display = "none";
anchor.download = torrentName;
this.$el.appendChild(anchor);
anchor.click();
setTimeout(() => {
this.$el.removeChild(anchor);
URL.revokeObjectURL(herf);
}, 0);
},
async getAndDownloadTorrent() {
if (!this.detailLink) {
this.$toast.display("无法获取下载链接。");
return;
}
try {
this.loading = true;
const { url, filename } = await this.getTorrentUrl(
this.detailLink,
this.title
);
await this.downloadTorrent(url, filename);
} catch (e) {
this.$toast.display(e.message);
} finally {
this.loading = false;
}
}
}
};
var __component__$2 = /* @__PURE__ */ normalizeComponent(
_sfc_main$2,
render$2,
staticRenderFns$2,
false,
null,
"f5ce47f3"
);
const TorrentDownloadItem = __component__$2.exports;
const CheckboxHeaderVM = Vue2.extend(CheckboxHeader);
const CheckboxItemVM = Vue2.extend(CheckboxItem);
const TorrentDownloadHeaderVM = Vue2.extend(TorrentDownloadHeader);
const TorrentDownloadItemVM = Vue2.extend(TorrentDownloadItem);
const ToolBarVM = Vue2.extend(ToolBar);
const LinksPopupVM = Vue2.extend(LinksPopup);
function mountListElement(el) {
const list = new Vue2({
data() {
return {
header: null,
all: [],
selected: [],
popupIndex: 10,
toolbars: []
};
},
computed: {
links() {
return this.selected.map((item) => item.magnet).filter((m) => !!m);
}
},
watch: {
links(val) {
const isEmpty = !val || val.length <= 0;
this.toolbars.forEach((t) => {
t.visible = !isEmpty;
});
}
},
mounted() {
this.$nextTick(function() {
const table = this.$el;
let tableContainer;
if (!table.parentNode || (tableContainer = table.parentNode.parentNode, !tableContainer || tableContainer.className.indexOf("table") < 0)) {
return;
}
if (table.tHead && table.tBodies) {
if (table.tHead.rows && table.tHead.rows.length > 0) {
this.insertHeaderToRow(table.tHead.rows[0]);
}
let index = 0;
for (let i = 0, len = table.tBodies.length; i < len; i++) {
let body = table.tBodies[i];
for (let j = 0, rowLen = body.rows.length; j < rowLen; j++) {
this.insertItemToRow(body.rows[j], index++);
}
}
} else {
if (table.rows) {
for (let i = 0, len = table.rows.length; i < len; i++) {
let row = table.rows[i];
if (i === 0) {
this.insertHeaderToRow(row);
} else {
this.insertItemToRow(row, i - 1);
}
}
}
}
this.initToolBars(tableContainer);
});
},
beforeDestroy() {
if (this.header) {
this.header.$off("change");
this.header = null;
}
this.all.forEach((item) => {
item.$off("change");
});
this.toolbars.forEach((t) => {
t.$off("copy");
t.$off("show");
});
this.all.splice(0, this.all.length);
this.selected.splice(0, this.selected.length);
this.toolbars.splice(0, this.toolbars.length);
},
methods: {
initToolBars(tableContainer) {
const headerToolbar = new ToolBarVM({
propsData: {
position: "top"
}
}).$mount();
headerToolbar.$on("copy", this.onCopyLinks);
headerToolbar.$on("show", this.onShowLinks);
const bottomToobar = new ToolBarVM({
propsData: {
position: "bottom"
}
}).$mount();
bottomToobar.$on("copy", this.onCopyLinks);
bottomToobar.$on("show", this.onShowLinks);
tableContainer.insertBefore(
headerToolbar.$el,
tableContainer.firstChild
);
tableContainer.appendChild(bottomToobar.$el);
this.toolbars.push(headerToolbar, bottomToobar);
},
insertHeaderToRow(row) {
if (row.cells.length <= 0)
return;
const firstCell = row.cells[0];
let sizeCell;
if (row.cells.length >= 5) {
sizeCell = row.cells[4];
}
const checkboxTH = new CheckboxHeaderVM().$mount();
checkboxTH.$on("change", this.onSelectAllChange);
row.insertBefore(checkboxTH.$el, firstCell);
this.header = checkboxTH;
if (sizeCell) {
const bittorrentDownloadTH = new TorrentDownloadHeaderVM().$mount();
row.insertBefore(bittorrentDownloadTH.$el, sizeCell);
}
},
insertItemToRow(row, index) {
if (row.cells.length <= 0)
return;
const firstCell = row.cells[0];
let sizeCell;
if (row.cells.length >= 5) {
sizeCell = row.cells[4];
}
const magnetLinkDOM = row.querySelector("td > .arrow-magnet");
const checkboxTD = new CheckboxItemVM({
propsData: {
index,
magnet: magnetLinkDOM ? magnetLinkDOM.href : ""
}
}).$mount();
const _self = this;
checkboxTD.$on("change", function(checked) {
_self.onItemSelectChange(checkboxTD, checked);
});
row.insertBefore(checkboxTD.$el, firstCell);
this.all.push(checkboxTD);
if (sizeCell) {
const detailLinkDom = row.querySelector("td.title > a");
const bittorrentDownloadTD = new TorrentDownloadItemVM({
propsData: {
index,
detailLink: detailLinkDom ? detailLinkDom.href : "",
title: detailLinkDom ? detailLinkDom.innerText : ""
}
}).$mount();
row.insertBefore(bittorrentDownloadTD.$el, sizeCell);
}
},
onSelectAllChange(checked) {
this.all.forEach(function(item) {
item.checked = checked;
});
if (checked) {
this.selected = [...this.all];
} else {
this.selected.splice(0, this.selected.length);
}
},
onItemSelectChange(item, checked) {
const selectedIndex = this.selected.indexOf(item);
if (checked && selectedIndex < 0) {
this.selected.push(item);
} else if (!checked && selectedIndex > -1) {
this.selected.splice(selectedIndex, 1);
}
if (this.header) {
this.header.checked = this.all.length === this.selected.length;
}
},
onCopyLinks(opts) {
const links = magnetLinksWithOptions(this.links, opts);
if (links.length > 0) {
try {
const content = links.join(opts.separator);
GM_setClipboard(content, "{ type: 'text', mimetype: 'text/plain'}");
this.$toast.display("复制成功!");
} catch (e) {
this.$toast.display("复制失败,请重试。");
}
}
},
onShowLinks(opts) {
const links = magnetLinksWithOptions(this.links, opts);
if (links.length > 0) {
const popup = new LinksPopupVM({
propsData: {
zIndex: this.popupIndex++,
links,
options: opts
}
}).$mount();
popup.$on("close", function() {
popup.$off("close");
try {
popup.$el.remove();
} catch (e) {
document.body.removeChild(popup.$el);
}
});
document.body.appendChild(popup.$el);
}
}
}
});
list.$mount(el);
}
var render$1 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("li", { staticClass: "tree-item", class: { "collection": this.isFolder, "last": this.isLast } }, [_vm.isFolder ? _c("div", { staticClass: "hitarea", class: { "collapsable-hitarea": _vm.isOpen, "last-hitarea": _vm.isLast }, on: { "click": _vm.toggle } }) : _vm._e(), _c("div", { class: ["title", _vm.icon], on: { "click": function($event) {
_vm.isFolder && _vm.toggle();
} } }, [_c("h5", [_vm._v(_vm._s(_vm.name))]), _c("span", { staticClass: "size" }, [_vm._v(_vm._s(_vm.totalSize))])]), _vm.isFolder ? _c("ul", { directives: [{ name: "show", rawName: "v-show", value: _vm.isOpen, expression: "isOpen" }] }, _vm._l(_vm.children, function(child, index) {
return _c("tree-item", _vm._b({ key: child.key, staticClass: "item", attrs: { "is-last": index === _vm.children.length - 1 } }, "tree-item", child, false));
}), 1) : _vm._e()]);
};
var staticRenderFns$1 = [];
const Videos = ["mp4", "rmvb", "avi", "mkv", "wmv", "flv", "ts"];
const Audios = ["mp3", "ogg", "wma", "wav", "aac", "flac", "mka", "cue"];
const Subtitles = ["sub", "idx", "sup", "sst", "srt", "ssa", "ass", "tts"];
const Images = ["jpg", "jpeg", "png", "gif", "bmp", "pdf", "webp"];
const Archives = ["rar", "rar5", "zip", "7z", "tar", "gz", "xz"];
const Documents = [
"txt",
"log",
"md",
"doc",
"docx",
"xls",
"xlsx",
"ppt",
"pptx",
"md5"
];
const _sfc_main$1 = {
name: "TreeItem",
props: {
parentKey: {
type: Number,
default: -1
},
name: {
type: String,
default: ""
},
level: {
type: Number,
default: 1
},
size: {
type: Number,
default: 0
},
children: {
type: Array,
default() {
return [];
}
},
isLast: {
type: Boolean,
default: false
},
expand: {
type: Boolean,
default: false
}
},
data() {
return {
isOpen: this.expand
};
},
computed: {
isFolder() {
return this.children && this.children.length > 0;
},
totalSize() {
let sum;
if (this.size > 0) {
sum = this.size;
} else {
const sizeList = this.sizeListWithItem({
size: this.size,
children: this.children
});
sum = sizeList.reduce((a, b) => a + b, 0);
}
return XBytes(sum, { iec: true, fixed: 1 });
},
icon() {
if (this.isFolder) {
return this.isOpen ? "folder-open" : "folder-close";
}
const ext = this.name.split(".").pop().toLowerCase();
switch (true) {
case Videos.indexOf(ext) > -1:
return "video";
case Images.indexOf(ext) > -1:
return "image";
case Archives.indexOf(ext) > -1:
return "archive";
case Audios.indexOf(ext) > -1:
return "audio";
case Documents.indexOf(ext) > -1:
return "document";
case Subtitles.indexOf(ext) > -1:
return "subtitle";
default:
return "unknown";
}
}
},
methods: {
toggle() {
this.isOpen = !this.isOpen;
},
sizeListWithItem(item) {
const children = item.children;
if (!children || children.length <= 0) {
return item.size ? [item.size] : [];
}
let list = [];
for (let i = 0, len = children.length; i < len; i++) {
let cList = this.sizeListWithItem(children[i]);
list.push(...cList);
}
return list;
}
}
};
var __component__$1 = /* @__PURE__ */ normalizeComponent(
_sfc_main$1,
render$1,
staticRenderFns$1,
false,
null,
"3ab763b5"
);
const TreeItem = __component__$1.exports;
var render = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("ul", { staticStyle: { "padding": "0", "margin": "0", "list-style": "none" } }, _vm._l(_vm.folders, function(folder, index) {
return _c("tree-item", _vm._b({ key: folder.key, attrs: { "is-last": index === _vm.folders.length - 1, "expand": true } }, "tree-item", folder, false));
}), 1);
};
var staticRenderFns = [];
const _sfc_main = {
name: "TreeRoot",
components: {
TreeItem
},
props: {
folders: {
type: Array,
default() {
return [];
}
}
}
};
var __component__ = /* @__PURE__ */ normalizeComponent(
_sfc_main,
render,
staticRenderFns,
false,
null,
null
);
const TreeRoot = __component__.exports;
const TreeRootVM = Vue2.extend(TreeRoot);
function folderTreeFromNodeList(fileNodeList) {
const map = {};
const list = [];
for (let i = 0, len = fileNodeList.length; i < len; i++) {
const fileNode = fileNodeList[i];
const fileSizeNode = fileNode.querySelector(".bt_file_size");
const nodeText = fileNode.innerText;
let fileSizeStr;
if (fileSizeNode) {
fileSizeStr = fileSizeNode.innerText.trim();
}
let filePath;
let fileBytes = 0;
if (fileSizeStr) {
const bytes = fileSizeStr.replace(/(\d+)bytes?/i, "$1");
if (!isNaN(+bytes)) {
fileBytes = +bytes;
} else {
fileBytes = XBytes.parseSize(fileSizeStr, { iec: false });
}
filePath = nodeText.substring(0, nodeText.indexOf(fileSizeStr)).trim();
} else {
filePath = nodeText.trim();
}
if (!filePath) {
filePath = `No. ${i + 1} - Unknown filename`;
}
let slice = filePath.split("/");
let parentKey = 0;
for (let j = 0, sLen = slice.length; j < sLen; j++) {
let fileName = slice[j];
let level = j + 1;
let baseName = filePath.substring(
0,
filePath.indexOf(fileName) + fileName.length
);
let key = hashCode(baseName);
if (!map[key]) {
let file = {
key,
parentKey,
name: fileName,
level,
size: level === sLen ? fileBytes : 0,
children: level === sLen ? null : []
};
map[key] = file;
list.push(file);
}
parentKey = key;
}
}
const root = [];
for (let i = 0, len = list.length; i < len; i++) {
let file = list[i];
if (!file.parentKey) {
root.push(file);
} else {
map[file.parentKey].children.push(file);
}
}
return root;
}
function mountFileListElement(el, title) {
const fileListNode = el.querySelector("ul");
const fileItemNodeList = el.querySelectorAll("ul > li");
if (!fileListNode || fileItemNodeList.length <= 0) {
return;
}
const folders = folderTreeFromNodeList(fileItemNodeList);
if (folders.length <= 0) {
return;
}
const tree = new TreeRootVM({
propsData: {
folders: (folders.length > 1 || folders[0].size) && title ? [
{
key: 0,
parentKey: -1,
name: title,
children: folders
}
] : folders
}
});
tree.$mount(fileListNode);
}
const ToastItemVM = Vue2.extend(ToastItem);
const toast = new ToastItemVM().$mount();
document.body.appendChild(toast.$el);
Object.defineProperty(Vue2.prototype, "$toast", { value: toast });
let topicListEl, fileListEl;
if (topicListEl = document.querySelector("#topic_list")) {
mountListElement(topicListEl);
if (typeof jQuery !== "undefined" && typeof jQuery.tablesorter !== "undefined") {
jQuery("#topic_list").tablesorter({ widgets: ["zebra"] });
jQuery("#topic_list").bind("sortStart", function() {
jQuery("#overlay").show();
}).bind("sortEnd", function() {
jQuery("#overlay").hide();
});
}
}
if (fileListEl = document.querySelector("#resource-tabs .file_list")) {
let title = "";
let titleEl;
if (titleEl = document.querySelector(".topic-title h3")) {
title = titleEl.innerText.trim();
}
mountFileListElement(fileListEl, title);
}
})(Vue, xbytes);