您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
direct download archive from list / sort gallery (in current page) / show full title in pure text
当前为
// ==UserScript== // @name ehx direct download // @namespace https://github.com/x94fujo6rpg/SomeTampermonkeyScripts // @version 0.52 // @description direct download archive from list / sort gallery (in current page) / show full title in pure text // @author x94fujo6 // @match https://e-hentai.org/* // @exclude https://e-hentai.org/mytags // @exclude https://e-hentai.org/mpv/* // @match https://exhentai.org/* // @exclude https://exhentai.org/mytags // @exclude https://exhentai.org/mpv/* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== // this script only work in Thumbnail mode (function () { 'use strict'; let api; let domain; let hid = true; let m = "[ehx direct download]: "; let key = "exhddl_list"; let defaultValue = []; let debug = true; let gallery_nodes; let gdata = []; let gcount = 0; let pcount = 0; let id_mainbox = "exhddl_activate"; let id_dd = "exhddl_ddbutton"; let id_puretext = "exhddl_puretext"; let id_sort_setting = "exhddl_sortsetting"; window.onload = main(); function myCss() { let s = document.createElement("style"); s.id = "ehx_direct_download_css"; document.head.appendChild(s); s.textContent = ` .puretext { overflow: hidden; min-height: 32px; line-height: 16px; margin: 6px 4px 0; font-size: 10pt; text-align: center; } `; } function main() { api = setApi(); domain = `https://${document.domain}`; if (!domain || !api) return print(`${m}domain or api is missing`); myCss() let link = document.location.href; if (link.includes(".php")) { return print(`${m}see php, abort`); } else if (link.includes("/g/")) { print(`${m}gallery page`); return setEvent(link); } else { print(`${m}normal start`); if (!checkDisplayMode) return wrongDisplayMode(); return setButton(); } } function checkDisplayMode() { let setting = document.getElementById("dms"); if (!setting) return false; setting = setting.querySelector("option[value='t']"); return setting.selected; } function wrongDisplayMode() { let pos = document.querySelector(".ido"); pos.insertAdjacentElement("afterbegin", newSpan("Display mode is not Thumbnail. Script stop")); } function newSpan(text = "") { let span = document.createElement("span"); Object.assign(span, { textContent: text, }); return span; } function newLine() { return document.createElement("br"); } function newSeparate() { return newSpan(" / "); } function setEvent(link) { let la = link.split("/"); if (la[3] === "g") { let gid = la[4]; let e = findEleByText("a", "Archive Download"); e.addEventListener("click", () => { updateList(gid); }); print(`${m}set trigger for updateList on gallery:${gid}`); } } function findEleByText(type, string) { let es = document.querySelectorAll(type); for (let index in es) { if (!isNaN(index)) { let e = es[index]; if (e.textContent.includes(string)) { return e; } } } } function setButton() { let pos = document.querySelector(".ido"); let bs = "width: max-content"; let box = document.createElement("div"); box.id = id_mainbox; let nodelist = [ newButton(id_dd, "Enable: Archive Download & Sorting & Show torrents Title", bs, downloadButton), newLine(), newButton(id_puretext, "Show Pure Text", bs, pureText), newLine(), ]; box = appendAll(box, nodelist); pos.insertAdjacentElement("afterbegin", box); if (hid) hlexg(); } function setSortingButton() { let pos = document.getElementById(id_mainbox); let bs = "width: max-content"; let ck = document.createElement("input"); Object.assign(ck, { type: "checkbox", id: id_sort_setting, checked: true, }); let lable = document.createElement("label"); Object.assign(lable, { htmlFor: id_sort_setting, textContent: "Descending", }); let nodelist = [ newButton("exhddl_sort_by_title", "Sort By Title", bs, () => { sortGalleryByKey("title"); }), newSeparate(), newButton("exhddl_sort_by_artist", "Sort By Artist", bs, () => { sortGalleryByKey("artist"); }), newSeparate(), newButton("exhddl_sort_by_group", "Sort By Group/Circle", bs, () => { sortGalleryByKey("group"); }), newLine(), newButton("exhddl_sort_by_date", "Sort By Date", bs, () => { sortGalleryByKey("gid"); }), newSeparate(), newButton("exhddl_sort_by_category", "Sort By Category", bs, () => { sortGalleryByKey("category"); }), newSeparate(), newButton("exhddl_sort_by_ex", "Sort By ???", bs, () => { sortGalleryByKey("expunged"); }), newLine(), ck, lable, ]; pos.querySelector("span").remove(); pos.querySelector("br").remove(); appendAll(pos, nodelist); } function setShowTorrent() { let nodelist = document.querySelectorAll(".gl1t"); nodelist.forEach(g => { let id = g.querySelector("a").href.split("/g/")[1].split("/")[0]; let torrent_list = getTorrentList(id); if (torrent_list) { let pos = g.querySelector(`#gallery_dl_${id}`); torrent_list.forEach((t, index) => { let span = newSpan(t); span.className = "puretext torrent_title"; span.style.display = "none"; //if (index != 0) pos.insertAdjacentElement("afterend", newLine()); pos.insertAdjacentElement("afterend", span); }); let bs = "width: max-content; align-self: center;"; let button = newButton(`t_title_${id}`, "Torrent List", bs, function () { let t_list = this.parentElement.querySelectorAll(".torrent_title"); t_list.forEach(e => e.style.display = (e.style.display == "none") ? "" : "none"); }); pos.insertAdjacentElement("afterend", button); } }); } function getTorrentList(gid = "") { let list = []; let torrents = gdata.find(g => g.gid == gid).torrents; if (torrents.length == 0) return false; torrents.forEach(t => { list.push(t.name); }); return list.reverse(); } function appendAll(node, nodeList) { nodeList.forEach(e => node.appendChild(e)); return node; } function processGdata() { let taglist = [ "artist", "group", ]; gdata.forEach(data => { taglist.forEach(tag_key => { data[tag_key] = data.tags.find(s => s.includes(`${tag_key}:`)); if (data[tag_key]) { data[tag_key] = data[tag_key].replace(`${tag_key}:`, ""); } else { data[tag_key] = ""; } }); }); } function getAllGalleryNode() { gallery_nodes = {}; let nodelist = document.querySelectorAll(".gl1t"); nodelist.forEach(node => { let title = node.querySelector(".glname"); let id = title.parentElement.href.split("/g/")[1].split("/")[0]; let deepcopy = node.cloneNode(true); copyOnclick(node, deepcopy, `#gallery_dl_${id}`); copyOnclick(node, deepcopy, `#t_title_${id}`); title = title.textContent; gallery_nodes[id] = { id: id, title: title, node: deepcopy, }; }); function copyOnclick(original, copy, css_selector) { let o = original.querySelector(css_selector); if (o) { copy.querySelector(css_selector).onclick = o.onclick; } } } function sortGalleryByKey(key = "") { if (!key) return; let sorted_id = getSortedGalleryID(gdata, key); let container = document.querySelector(".itg.gld"); getAllGalleryNode(); removeAllGallery(); sorted_id.forEach(id => container.appendChild(gallery_nodes[id].node)); } function removeAllGallery() { let nodelist = document.querySelectorAll(".gl1t"); nodelist.forEach(e => e.remove()); } function getSortedGalleryID(object_list, sort_key) { let newlist = []; let descending = document.getElementById(id_sort_setting); descending = descending.checked ? true : false; newlist = object_list.sort((a, b) => { if (descending) { return a[sort_key] < b[sort_key] ? 1 : -1; } else { return a[sort_key] > b[sort_key] ? 1 : -1; } }); let id_list = []; if (newlist) newlist.forEach(item => id_list.push(item.gid)); return id_list; } function newButton(e_id, e_text, e_style, e_onclick) { let e = document.createElement("button"); return Object.assign(e, { id: e_id, textContent: e_text, style: e_style, onclick: e_onclick, }); } function setApi() { let eh = "https://api.e-hentai.org/api.php"; let ex = "https://exhentai.org/api.php"; let link = document.location.href; if (link.indexOf("//exhentai") != -1) { print(`${m}set api as ${ex}`); return ex; } else if (link.indexOf("//e-hentai") != -1) { print(`${m}set api as ${eh}`); return eh; } return false; } function hlexg() { let w = document.querySelectorAll("s"); if (w.length > 0) w.forEach(ele => ele.parentElement.parentElement.parentElement.parentElement.style.backgroundColor = "GoldenRod"); } function pureText() { document.getElementById(id_puretext).remove(); document.getElementById(id_mainbox).querySelector("br").remove(); let gallery = document.querySelectorAll(".gl1t"); gallery.forEach(ele => { let e = document.createElement("span"); e.textContent = ele.querySelector("a[href]").textContent; e.className = "puretext"; let pos = ele.querySelector(".gdd"); if (pos) { pos.insertAdjacentElement("beforebegin", e); } else { pos = ele.querySelector(".gl3t"); pos.insertAdjacentElement("afterend", e); } }); } function downloadButton() { let pos = document.getElementById(id_mainbox); document.getElementById(id_dd).remove(); pos.insertAdjacentElement("afterbegin", newSpan("Processing... Please Wait")); acquireGalleryData(); setLinkToNewTab(); } function updateGalleryStatus() { let list = GM_getValue(key, defaultValue).split(","); gdata.forEach(g => { let dl_button = document.querySelector(`#gallery_dl_${g.gid}`); if (list.indexOf(`${g.gid}`) != -1) { dl_button.style.color = "gray"; dl_button.style.backgroundColor = "transparent"; } }); } function setLinkToNewTab() { let gallery = document.querySelectorAll(".gl1t"); gallery.forEach(g => { g.querySelectorAll("a").forEach(a => { if (a.href.includes("/g/")) a.target = "_blank"; }); }); } function acquireGalleryData() { let gallery = document.querySelectorAll(".gl1t"); let gc = 0; if (gallery) { print(`${m}acquire gallery data`); let data = { method: "gdata", gidlist: [], namespace: 1 }; let alldata = []; let count = 0; let glist = []; gallery.forEach((ele, index) => { let link = ele.querySelector(`a[href*='${domain}/g/']`).href.split("/"); if (link[3] === "g") { let gid = link[4]; let gtoken = link[5]; if (gid && gtoken) { glist.push([gid, gtoken]); count++; gc++; if (count === 25 || index === gallery.length - 1) { count = 0; let newdata = Object.assign({}, data); newdata.gidlist = Object.assign([], glist); alldata.push(newdata); glist = []; } } } }); gcount = gc; // save gallery count print(`${m}gallery queue length:${alldata.length}, total gallery count:${gc}`); if (alldata.length != 0) { print(`${m}start sending request`); requestData(alldata); } else { print(`${m}gallery queue is empty`); } } } function requestData(datalist) { for (let index = 0; index < datalist.length; index++) { setTimeout(() => { print(`${m}sending request${index + 1}`); let data = datalist[index]; if (data) myApiCall(data, index + 1); }, 1000 * index); } } function directDL(data, index) { data = JSON.parse(data); print(`${m}process data from request batch:${index}, gallery count:${Object.keys(data.gmetadata).length}`); let list = GM_getValue(key, defaultValue); if (list.length != 0) list.split(","); let gidlist = []; data.gmetadata.forEach(g => { gdata.push(g); let archivelink = `${domain}/archiver.php?gid=${g.gid}&token=${g.token}&or=${g.archiver_key}`; let glink = `${domain}/g/${g.gid}/${g.token}/`; let gallery = document.querySelector(`a[href="${glink}`); if (gallery) { let dlbutton = document.createElement("button"); Object.assign(dlbutton, { id: `gallery_dl_${g.gid}`, className: "gdd", style: "width: max-content; align-self: center;", textContent: "Archive Download", }); dlbutton.onclick = function () { let s = document.getElementById(dlbutton.id).style; s.color = "gray"; s.backgroundColor = "transparent"; visitGallery(glink); updateList(g.gid); return my_popUp(archivelink, 480, 320); }; if (list.indexOf(`${g.gid}`) != -1) { dlbutton.style.color = "gray"; dlbutton.style.backgroundColor = "transparent"; print(`${m}gallery [${dlbutton.id}] is in downloaded list, set as downloaded`); } let pos = gallery.parentElement.querySelector(".puretext"); if (!pos) pos = gallery.parentElement.querySelector(".gl3t"); pos.insertAdjacentElement("afterend", dlbutton); gidlist.push(dlbutton.id); pcount++; } }); print(`${m}request batch:${index} done`); if (gcount === pcount) { print(`${m}all request done`); print(`${m}initializing sorting`); print(`${m}process data`); processGdata(); print(`${m}setup sorting button`); setSortingButton(); print(`${m}setup show torrent title button`); setShowTorrent(); setInterval(updateGalleryStatus, 3000); } } function my_popUp(URL, w, h) { window.open( URL, `_pu${Math.random().toString().replace(/0\./, "")}`, `toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0 ,width=${w},height=${h},left=${(screen.width - w) / 2},top=${(screen.height - h) / 2}` ); return false; } function myApiCall(data, index) { let request = new XMLHttpRequest(); request.open("POST", api); request.setRequestHeader("Content-Type", "application/json"); request.withCredentials = true; request.onreadystatechange = function () { if (request.readyState == 4) { if (request.status == 200) { print(`${m}request${index} complete`); return directDL(request.responseText, index); } else { print(`${m}request${index} failed [status: ${request.status}]`); print(request); return; } } }; request.send(JSON.stringify(data)); } function visitGallery(link) { if (link) { // send request to server, not sure this count or not. (no effect to link states) let r = new XMLHttpRequest(); r.open("get", link, true); r.onreadystatechange = function () { if (r.readyState == 4) { if (r.status == 200) { print(`${m}server request success, gallery:${link}`); } else { print(`${m}server request failed, gallery:${link}`); print(r); } } }; r.send(); // trigger :visited let current = window.location.href; history.pushState({}, "", link); // add link to history. this will change current winodw link. print(`${m}add history, link:${window.location.href}`); history.pushState({}, "", current); // change it back. } } function updateList(gid) { gid = `${gid}`; // convert to string let list = GM_getValue(key, defaultValue); if (list.length != 0) { let count = 0; list = list.split(","); if (list.indexOf(gid) != -1) return print(`${m}[${gid}] is already in the list, abort`); list.push(gid); while (list.length > 10000) { let r = list.shift(); print(`${m}reach limit, remove [${r}]`); count++; if (count > 100) return print(`${m}unknow error while removing old data, script stop`); } } else { print(`${m}no list found, creat new list`); list = [gid]; } list = list.join(); GM_setValue(key, list); print(`${m}add [${gid}] to list. [list_size:${list.length}, list_length:${list.split(",").length}]`); } function print(...any) { if (debug) console.log(...any); } })();