// ==UserScript==
// @name EH Enhance(E绅士增强)
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Scroll to top/comment/bottom, copy gallery title, search selected text, search multiple tags.(滚动到顶部/讨论区/底部,复制画廊标题,搜索选中文本,多标签搜索)
// @author ssnangua
// @match https://e-hentai.org/*
// @match https://exhentai.org/*
// @icon https://e-hentai.org/favicon.ico
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const chinese = {
search: "搜索",
language: "中文",
uncensored: "无修正",
wnacg: "绅士漫画",
hitomi: "hitomi",
yhg: "移花宫",
es: "ES",
copy: "复制",
searchSelectedTags: "搜索选中的标签",
toTop: "滚动到顶部",
toComment: "滚动到评论区",
toBottom: "滚动到底部",
toggleLanguage: "Change To English",
};
const english = {
search: "Search",
language: "English",
uncensored: "Uncensored",
wnacg: "wnacg",
hitomi: "hitomi",
yhg: "yhg",
es: "ES",
copy: "Copy",
searchSelectedTags: "Search Selected Tags",
toTop: "Scroll To Top",
toComment: "Scroll To Comment",
toBottom: "Scroll To Bottom",
toggleLanguage: "切换为中文",
};
const lang = localStorage.language || navigator.language;
const isChinese = lang === "zh-CN";
const t = isChinese ? chinese : english;
const EH = location.origin + "/?f_search=%s";
const WNACG = "https://www.wnacg.com/search/?q=%s";
const HITOMI = "https://hitomi.la/search.html?%s";
const YHG = "https://yhg007.com/search-%s-0-0-1.html";
const ES = "es:%s";
const SEARCH_BAR = [
{ label: t.search, append: "", url: EH },
{ label: t.language, append: isChinese ? "language:chinese$" : "language:english$", url: EH },
{ label: t.uncensored, append: "other:uncensored$", url: EH },
{ label: t.wnacg, append: "", url: WNACG },
{ label: t.hitomi, append: "", url: HITOMI },
{ label: t.yhg, append: "", url: YHG },
{ label: t.es, append: "", url: ES },
];
/**********************************************/
/* 滚动到 */
/**********************************************/
const $scrollToBar = document.createElement("div");
$scrollToBar.className = "eh-scroll-to-bar";
document.body.appendChild($scrollToBar);
const $comment = document.querySelector("#cdiv");
$scrollToBar.appendChild(createGotoButton("🔝", t.toTop, 0));
if ($comment) $scrollToBar.appendChild(createGotoButton("💬", t.toComment, $comment));
$scrollToBar.appendChild(createGotoButton("⬇️", t.toBottom, 1000000));
// const $langButton = createButton(isChinese ? "🇨🇳" : "🇬🇧", () => {
// localStorage.language = isChinese ? "en-US" : "zh-CN";
// location.reload();
// });
// $langButton.dataset.tip = t.toggleLanguage;
// $langButton.style.marginTop = "20px";
// $scrollToBar.appendChild($langButton);
function createGotoButton(label, tip, scrollTopOrElement) {
const $button = createButton(label, () => {
if (typeof scrollTopOrElement === "number") {
document.body.parentElement.scrollTo({
top: scrollTopOrElement,
behavior: "smooth",
});
} else {
scrollTopOrElement.scrollIntoView({ behavior: "smooth" });
}
});
$button.dataset.tip = tip;
return $button;
}
/**********************************************/
/* 画廊 */
/**********************************************/
// 复制标题
document.querySelectorAll("h1#gn, h1#gj").forEach(($h1) => {
const text = $h1.textContent.trim();
if (text) {
const $copyButton = createButton(t.copy, async (e) => {
await navigator.clipboard.writeText(text);
e.target.textContent = t.copy + "✔️";
setTimeout(() => (e.target.textContent = t.copy), 1000);
});
$copyButton.className = "eh-copy";
$h1.appendChild($copyButton);
}
});
// 多标签搜索
const $taglist = document.querySelector("#taglist");
if ($taglist) {
const $tags = [...$taglist.querySelectorAll("a")];
$tags.forEach(($tag) => {
$tag.addEventListener("click", () => {
$tag.selected = !$tag.selected;
$tag.parentNode.classList.toggle("selected", $tag.selected);
$act2.style.display = $tags.some(($tag) => $tag.selected) ? "" : "none";
});
});
const $act2 = document.createElement("div");
$act2.id = "tagmenu_act2";
$act2.style.display = "none";
$act2.innerHTML = `
<img src="https://ehgt.org/g/mr.gif" class="mr" alt=">">
<a id="search_tags" href="#">${t.searchSelectedTags}</a>
`;
$taglist.appendChild($act2);
$act2.querySelector("#search_tags").addEventListener("click", () => {
const tags = $tags
.filter(($tag) => $tag.selected)
.map(($tag) => {
const [tc, td] = $tag.onclick
.toString()
.match(/'(.*?)'/)[1]
.split(":");
return `${tc}:"${td}$"`;
});
window.open(EH.replace("%s", tags.join("+")));
});
}
// 划词搜索
let selectedText;
const $searchBar = document.createElement("div");
$searchBar.className = `eh-search-bar`;
$searchBar.addEventListener("mouseup", (e) => e.stopPropagation());
document.body.appendChild($searchBar);
SEARCH_BAR.forEach(({ label, append, url }) => {
const $button = createButton(label, () => {
const text = (selectedText + " " + append).trim();
window.open(url.replace("%s", text));
});
$searchBar.appendChild($button);
});
window.addEventListener("mouseup", (e) => {
selectedText = document.getSelection().toString().trim();
if (selectedText) {
$searchBar.style.display = "flex";
const left = Math.min(e.x, window.innerWidth - $searchBar.offsetWidth - 20);
const top = Math.min(e.y + 20, window.innerHeight - $searchBar.offsetHeight);
$searchBar.style.left = left + "px";
$searchBar.style.top = top + "px";
} else {
$searchBar.style.display = "none";
}
});
function createButton(label, onClick) {
const $button = document.createElement("button");
$button.textContent = label;
$button.addEventListener("click", onClick);
return $button;
}
function prependChild(parent, child) {
parent.insertBefore(child, parent.firstChild);
}
GM_addStyle(`
.ehs-eh {
--panel-bg: #edebdf;
--panel-border: 1px solid #5c0d12;
--tag-selected-bg: #d5c5c6;
--tag-selected-color: royalblue;
}
.ehs-ex {
--panel-bg: #4f535b;
--panel-border: 1px solid #000000;
--tag-selected-bg: #34353b;
--tag-selected-color: skyblue;
}
.eh-scroll-to-bar {
display: flex;
flex-flow: column;
gap: 10px;
z-index: 10;
position: fixed;
right: 30px;
top: 20px;
& button {
width: 40px;
height: 40px;
font-size: 18px;
cursor: pointer;
position: relative;
/*&:hover::after {
content: attr(data-tip);
display: inline-block;
white-space: nowrap;
font-size: 14px;
background: var(--panel-bg);
border: var(--panel-border);
padding: 5px 10px;
position: absolute;
right: 42px;
top: 50%;
transform: translateY(-50%);
}*/
}
}
.eh-copy {
margin-left: 5px;
cursor: pointer;
}
.eh-search-bar {
display: none;
position: fixed;
z-index: 10000;
padding: 5px;
background: var(--panel-bg);
border: var(--panel-border);
& button {
margin: 2px;
white-space: nowrap;
cursor: pointer;
}
}
#taglist td>div a[style="color: blue;"] {
color: var(--tag-selected-color) !important;
}
#taglist td>div.selected {
background: var(--tag-selected-bg);
}
#tagmenu_act2 {
margin: 0;
float: left;
width: 554px;
height: 26px;
font-size: 9pt;
}
#tagmenu_act2 img {
padding-bottom: 1px;
}
#tagmenu_act2 a {
text-decoration: none;
font-weight: bold;
}
`);
})();