您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show tags on hover.
// ==UserScript== // @name Tag Preview // @version 2.02 // @description Show tags on hover. // @author Hauffen // @runat document-start // @include /https?:\/\/(e-|ex)hentai\.org\/.*/ // @require https://code.jquery.com/jquery-3.3.1.min.js // @namespace https://greasyfork.org/users/285675 // ==/UserScript== (function() { let $ = window.jQuery, tags = {}; const elem = {0: '.gl3m a', 1: '.gl3m a', 2: '.gl3c a', 4: '.gl3t a'}; const defaultNamespace = "misc"; const spl = document.URL.split('/'); var element, title; if ((spl[3].substr(0, 1).match(/[?#fptw]/i) && !spl[3].startsWith('toplist')) || !spl[3]) { if ($('#tagPreview')) return; var $tagP = $('<div id="tagPreview">'); $tagP.css({ position: 'absolute', zIndex: '2', visiblility: 'hidden !important', maxWidth: '400px', background: window.getComputedStyle(document.getElementsByClassName('ido')[0]).backgroundColor, border: '1px solid #000', padding: '10px' }); $tagP.appendTo("body"); $('#tagPreview').css('visibility', 'hidden'); element = elem[$(".searchnav div > select > option:selected").index()]; $('.itg').on('mouseover', `${element}`, function(e) { if(document.getElementById('tagPreview').children.length > 2) { $tagP.empty(); } title = this.children[0].title; // Save the title so we can put it back later, probably unnecessary this.children[0].title = ""; // Clear the title so we don't have it over our new window var str = this.href.split('/'); generateRequest(str[4], str[5]); var posY, posX = (e.pageX + 432 < screen.width) ? e.pageX + 10 : e.pageX - 412; var scrollHeight = $(document).height(); var scrollPosition = $(window).height() + $(window).scrollTop(); if ((scrollHeight - scrollPosition) < (scrollHeight / 10)) { posY = (e.pageY + 300 < scrollHeight) ? e.pageY + 10 : e.pageY - 300; } else { posY = e.pageY + 10; } $tagP.css({ left: posX, top: posY, border: '1px solid ' + window.getComputedStyle(document.getElementsByTagName("a")[0]).getPropertyValue("color"), visibility: 'visible' }); $('#tagPreview').css('visibility', 'visible'); }).on('mousemove', `${element}`,function(e) { var posY, posX = (e.pageX + 432 < screen.width) ? e.pageX + 10 : e.pageX - 412; var scrollHeight = $(document).height(); var scrollPosition = $(window).height() + $(window).scrollTop(); if ((scrollHeight - scrollPosition) < (scrollHeight / 10)) { posY = (e.pageY + document.getElementById('tagPreview').offsetHeight < window.innerHeight) ? e.pageY + 10 : e.pageY - 10 - document.getElementById('tagPreview').offsetHeight; } else { posY = e.pageY + 10; } $tagP.css({ visibility:'visible', top: posY, left: posX }); $('#tagPreview').css('visibility', 'visible'); }).on('mouseout', `${element}`, function() { this.children[0].title = title; // Put the saved title back $tagP.css({ visibility:'hidden' }); $('#tagPreview').css('visibility', 'hidden'); $tagP.empty(); // Clear out the tag }); $(document).on('scroll', function() { $('#tagPreview').css('visibility', 'hidden'); }); } else { return; } /** * Generate the inner HTML for the tag preview window * @param {JSON} apirsp - The E-H API response */ function generateListing(apirsp) { generateTags(apirsp); // We actually have to generate the tag list from the raw JSON file $('#tagPreview').append(`<h1 id="gn">${apirsp.title}</h1><h1 id="gj">${apirsp.title_jpn}</h1>`); let taglist = "<div id='taglist' style='height:fit-content;'><table><tbody>"; for (const namespace in tags) { taglist += `<tr><td class="tc">${namespace}:</td><td>`; for (var i = 0; i < tags[namespace].length; i++) { taglist += `<div id="td_${namespace}:${tags[namespace][i]}" class="gt" style="opacity:1.0"><a id="ta_${namespace}:${tags[namespace][i]}" href="${document.location.origin}/tag/${namespace}:${tags[namespace][i]}">${tags[namespace][i]}</a></div>`; } taglist += "</td></tr>"; } taglist += "</tbody></table></div>"; $('#tagPreview').append(taglist); } /** * Converts the tag listing within the API response to a categorized array * @param {JSON} apirsp - The E-H API response */ function generateTags(apirsp) { tags = {}; // Reset the tags array for each new tag listing if (Array.isArray(apirsp.tags)) { for (const jsonTag of apirsp.tags) { const stringTag = getJsonString(jsonTag); if (stringTag === null) { continue; } const {tag, namespace} = getTagAndNamespace(stringTag); let namespaceTags; if (tags.hasOwnProperty(namespace)) { namespaceTags = tags[namespace]; } else { namespaceTags = []; tags[namespace] = namespaceTags; } namespaceTags.push(tag); } } } /** * Generate the JSON request for the E-H API * @param {Integer} gid - The gallery ID * @param {String} token - The gallery token */ function generateRequest(gid, token) { var reqList = [[gid, token]]; // We use an array for our gidlist, since the API can handle up to 25 galleries per request var request = {"method": "gdata", "gidlist": reqList, "namespace": 1}; var req = new XMLHttpRequest(); req.onreadystatechange = e => { if (req.readyState == 4) { if (req.status == 200) { var apirsp = JSON.parse(req.responseText); for (var i = 0; i < apirsp.gmetadata.length; i++) generateListing(apirsp.gmetadata[i]); } else { console.error(); } } } req.open("POST", document.location.origin + "/api.php", true); // Due to CORS, we need to use the API on the same domain as the script req.send(JSON.stringify(request)); } // Helper functions function getTagAndNamespace(tag) { const pattern = /^(?:([^:]*):)?([\w\W]*)$/; const match = pattern.exec(tag); return (match !== null) ? ({ tag: match[2], namespace: match[1] || defaultNamespace }) : ({ tag: tag, namespace: defaultNamespace }); } function toProperCase(text) { return text.replace(/(^|\W)(\w)/g, (m0, m1, m2) => `${m1}${m2.toUpperCase()}`); } function getJsonString(value) { if (typeof(value) === "string") { return value; } if (typeof(value) === "undefined" || value === null) { return value; } return `${value}`; } })();