From 7c0957badc38f7e20e0a4351328c9f5f096fea1d Mon Sep 17 00:00:00 2001 From: Fabio P <7722100+fp555@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:15:35 +0100 Subject: [PATCH] Use E-H API to fetch tags --- .github/build.sh | 20 +++++++++ .github/workflows/tag_release.yml | 24 +++------- LICENSE | 2 +- script.meta.js | 10 ++--- src/icon.svg | 2 +- src/script.js | 73 +++++++++++++++++++++---------- src/style.css | 35 ++++++++++----- src/tooltip.html | 2 +- 8 files changed, 108 insertions(+), 60 deletions(-) create mode 100755 .github/build.sh diff --git a/.github/build.sh b/.github/build.sh new file mode 100755 index 0000000..ade8446 --- /dev/null +++ b/.github/build.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +echo "::group::Version check" +echo "Github tag: $GITHUB_REF_NAME" +echo "Version tag: $(awk '/@version/ {printf "v%s",$3}' script.meta.js)" +echo "Resource tag: $(awk '/@resource/ {split($4,F,"/"); print F[8]}' script.meta.js)" +[[ $(awk '/@version/ {printf "v%s",$3}' script.meta.js) == $GITHUB_REF_NAME ]] +[[ $(awk '/@resource/ {split($4,F,"/"); print F[8]}' script.meta.js) == $GITHUB_REF_NAME ]] +echo "::endgroup::" + +echo "::group::Building userscript..." +cat script.meta.js src/script.js > script.user.js +readlink -f script.user.js +echo "::endgroup::" + +echo "::group::Building JSON bundle..." +shopt -s extglob +jq -Rn -f .github/filter.jq src/!(script.js) > content.json +readlink -f content.json +echo "::endgroup::" diff --git a/.github/workflows/tag_release.yml b/.github/workflows/tag_release.yml index 2f7a18b..db3dfc3 100644 --- a/.github/workflows/tag_release.yml +++ b/.github/workflows/tag_release.yml @@ -12,30 +12,16 @@ jobs: new_release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - name: Version check - run: "[[ $(awk '/@version/ {printf \"v%s\",$3}' script.meta.js) = ${{ github.ref_name }} ]]" - - - name: Resource version check - run: "[[ $(awk '/@resource/ {split($4,F,\"/\"); print F[8]}' script.meta.js) = ${{ github.ref_name }} ]]" + - uses: actions/checkout@v4 - name: Build userscript - run: cat script.meta.js src/script.js > script.user.js - - - name: Build JSON bundle - run: | - shopt -s extglob - jq -Rn -f .github/filter.jq src/!(script.js) > content.json + run: .github/build.sh - name: Create release draft - uses: softprops/action-gh-release@v0.1.14 + uses: ncipollo/release-action@v1 with: name: Release ${{ github.ref_name }} draft: true prerelease: false - fail_on_unmatched_files: true - files: | - script.user.js - content.json - + artifacts: "script.user.js,content.json" + artifactErrorsFailBuild: true diff --git a/LICENSE b/LICENSE index 422b1aa..edb01ec 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2022 fp555 +Copyright (c) 2018-2023 fp555 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/script.meta.js b/script.meta.js index 1f90f1f..1ebf9c7 100644 --- a/script.meta.js +++ b/script.meta.js @@ -2,7 +2,7 @@ // @name E(x)Hentai Tags Preview // @author fp555 // @namespace fp555/exh-tags-preview -// @version 1.8.6 +// @version 1.9.0 // @description Adds a tags tooltip while hovering on gallery links. // @match https://e-hentai.org/ // @match https://e-hentai.org/?f_search=* @@ -28,16 +28,16 @@ // @grant GM_getResourceText // @grant GM_getValue // @grant GM_setValue -// @resource content https://github.com/fp555/exh-tags-preview/releases/download/v1.8.6/content.json -// @downloadURL https://github.com/fp555/exh-tags-preview/releases/latest/download/script.user.js -// @homepage https://github.com/fp555/exh-tags-preview +// @resource content https://github.com/fp555/exh-tags-preview/releases/download/v1.9.0/content.json +// @downloadURL https://github.com/fp555/exh-tags-preview/releases/latest/download/script.user.js +// @homepage https://github.com/fp555/exh-tags-preview // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAACr1BMVEVHcExdWlY7ODUmJCNtZ18WEQxva2o1NC0bFg9gXlcXFRG7ubNZWVRCPzw5ODEYFA8vLSokHxlMSEIoJSE0MiwpJB4gGhQ7OzcrKSQeGxgYEg9HREAxLy2SgHaUh3okIhtFPzhnYVklHRc4MSs8NzJEPjUgIB0jIB03LiFUTUJLTEotJyJQTkppZF9za2VVVU1ORj0wLileUkg3MC4tJB0zLCdEOS8uLig5Miqdk4gqKCVDPTZcU0suKyocGxh7aV2loJUvLSmHeGxjXVJaUkh3c2gXFROEd2xmXFZ4bF9MRj85Myw8MyxTSUFSRkI8NzU1KiNmVkt8b2McFxSqn5FhXVcjHx0ZFxhDOzGckYg4LiWAb2FcUEX///////3///7//v8EAwH//v4LBgIOBgIBAAAXEQkQBwMPCQP+//4SCAX///3+///+/vz9//8aEAccEwohGhEUCwQUCwf9/v78/PoUEAcdFREnHBIHBQP29vQXDAYMCAQXFBEWEAs2Kh8RDQkjFw3JyMUaEQz6+vkOCwcTEgr9/PwRCwXn5+UyJx0mGQ7My8kdFg0iHBf5+Pjq6uksHxeopqMpHxaUk5Hv7+7f3962tbMhEwonIRwtIhc1MS5oZ2RdW1k9MieEgoLy8vB/fn329/dNPjInJST09PPAvrwSEA7U1NEqIhpHNisPDQTFwr7GxcP6/PxMS0qamZc+OzmLiIRbSkMxKiK6ubgvJR3//v9IR0a0sq7c2dXm5OFYVVHX1tNCQT1SUU3Rz85RR0AZGRhycW+Li4kfHBssHxCqqKYtLCshIB+wrqzd3Nifn5tta2nh4d9QTUuSkIxjYmBGRUFPQDiOhXutraiioJ2ioZ82Kic+LSE7NjA5OTb29e5WRzfAurSEeXV2cm57ennLx77V0MmajoRhjcuMAAAAknRSTlMAGytOCv0EDPsy5g8TXKL1SOlJ2M/L90mEjewjORaJ4HuZ9LeN45e4/JI672hhTnncrPl8+uXyvTAjo4etX+CuMtjdJshxwsf9vbiR6Y2fcN77zc1TgHSExjnynv3//////////////////////////////////////////////////////////////////////vDQa8UAAAdVSURBVFjD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 // ==/UserScript== /* MIT License * https://raw.githubusercontent.com/fp555/exh-tags-preview/master/LICENSE * - * Copyright (c) 2018-2022 fp555 + * Copyright (c) 2018-2024 fp555 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/icon.svg b/src/icon.svg index 9297a41..79edd14 100644 --- a/src/icon.svg +++ b/src/icon.svg @@ -1,4 +1,4 @@ - + diff --git a/src/script.js b/src/script.js index c4c6ee0..468177c 100644 --- a/src/script.js +++ b/src/script.js @@ -1,28 +1,32 @@ ((args) => { "use strict"; - + // save defaults on 1st run for(const c in args) GM_getValue("exhtp." + c, false) || GM_setValue("exhtp." + c, args[c]); - + + // are we on fjords? + const exh = location.host.substr(0,2) === "ex"; + // setup resources and CSS const content = JSON.parse(GM_getResourceText("content")); GM_addStyle(content.style); - + // options panel setup const op = document.createRange().createContextualFragment(content.options); op.querySelector(`input[name=mode][value=${args.mode}]`).checked = true; args.views.split('').forEach(v => op.querySelector(`input[name=views][value=${v}]`).checked = true); op.querySelector("input[name=newtab]").checked = args.newtab; const ttopt = op.querySelector("#ttopt"); - ttopt.onchange = e => { + ttopt.onchange = function(e) { e.stopPropagation(); // change events will all bubble here, no need to add listeners to all checkboxes GM_setValue("exhtp.mode", document.querySelector("input[name=mode]:checked").value); GM_setValue("exhtp.views", [...document.querySelectorAll("input[name=views]:checked")].map(v => v.value).join('')); GM_setValue("exhtp.newtab", document.querySelector("input[name=newtab]").checked); }; - ttopt.classList.add(window.location.hostname === "exhentai.org"? "exstyle" : "ehstyle"); + ttopt.classList.add(exh? "exstyle" : "ehstyle"); document.body.appendChild(op); - + + // main switch(window.location.pathname) { case "/upld/manage": // fix exh my uploads document.querySelectorAll("td.gtc5>a:first-child").forEach(a1 => { @@ -32,40 +36,63 @@ a1.after(stats); }); break; - + case "/upld/managegallery": // fix exh stats link document.querySelector("a[href*='stats.php']").hostname = "e-hentai.org"; break; - - default: // setup tooltip div + + default: // setup tooltip if(args.views.includes(document.querySelector(".searchnav > div:last-child > select").value)) { let gsel = ".glink"; document.body.appendChild(document.createRange().createContextualFragment(content.tooltip)); const tt = document.querySelector("#tagstt"); - tt.classList.add(window.location.hostname === "exhentai.org"? "exstyle" : "ehstyle"); - - if(args.mode === "icon") { // setup icon - document.querySelectorAll(".glname").forEach(g => g.appendChild(document.createRange().createContextualFragment(content.icon))); - gsel = ".glname>svg"; + tt.classList.add(exh? "exstyle" : "ehstyle"); + // setup icon + if(args.mode === "icon") { + document.querySelectorAll(".gl3m.glname,.gl3c.glname,.gl6t").forEach(g => g.appendChild(document.createRange().createContextualFragment(content.icon))); + gsel = ".svgicon"; } document.querySelectorAll(gsel).forEach(g => g.onpointerover = e => { const eoutprom = new Promise(resolve => g.onpointerout = eout => resolve(eout)); const tagprom = async () => { - const xhr = await window.fetch(e.target.closest("td.gl3m,td.gl3c,div.gl1t").querySelector("a").href); + // fetch gallery tags + const xhr = await fetch("https://api.e-hentai.org/api.php", { + method: "POST", + headers: {"Content-Type": "application/json;charset=utf-8"}, + body: JSON.stringify({ + method: "gdata", + namespace: 1, + gidlist: [e.target.closest("td.gl3m,td.gl3c,div.gl1t").querySelector("a").href.match(/(\d+)\/(\w+)\/$/).splice(1)] + }) + }); if(!xhr.ok) throw new TypeError("error " + xhr.status); - const response = await xhr.text(); - tt.replaceChildren(document.createRange().createContextualFragment(response).querySelector("div#taglist>table")); - tt.style.setProperty("--t", `${(window.innerHeight - e.clientY < tt.offsetHeight)? e.pageY - tt.offsetHeight : e.pageY}px`); - tt.style.setProperty("--l", `${(window.innerWidth - e.clientX < tt.offsetWidth)? e.pageX - tt.offsetWidth : e.pageX}px`); - tt.style.setProperty("--v", "visible"); + xhr.json().then(response => { + const tagsmap = new Map(); + response.gmetadata[0].tags.map(t => t.match(/(.+):(.+)/).slice(1)).forEach(([k, v]) => tagsmap.set(k, tagsmap.has(k)? [...tagsmap.get(k), v] : [v])); + // create tags table + [...tagsmap.keys()].forEach(k => { + const tds = [document.createElement("td"), document.createElement("td")]; + tds[0].classList.add("tc"); + tds[0].append(`${k}:`); + tagsmap.get(k).forEach(v => { + const vdiv = document.createElement("div"); + vdiv.classList.add("gt"); + vdiv.append(`${v}`); + tds[1].append(vdiv); + }); + tt.querySelector("tbody").appendChild(document.createElement("tr")).append(...tds); + }); + tt.style.setProperty("--t", `${(window.innerHeight - e.clientY < tt.offsetHeight)? e.pageY - tt.offsetHeight : e.pageY}px`); + tt.style.setProperty("--l", `${(window.innerWidth - e.clientX < tt.offsetWidth)? e.pageX - tt.offsetWidth : e.pageX}px`); + tt.style.setProperty("--v", "visible"); + }); }; // async functions always return a promise Promise.all([eoutprom, tagprom()]).then(() => { // make sure we have both event and tags before dismissing tooltip tt.style.setProperty("--v", "hidden"); - tt.replaceChildren(); // remove everything + tt.querySelector("tbody").replaceChildren(); // remove everything }).catch((error) => console.error(error.message)); }); }; - // open galleries in a new tab if(args.newtab) document.querySelectorAll(".gl3m.glname>a,.gl3c.glname>a,.gl1e>div>a,.gl2e>div>a,.gl1t>a,.gl4t.glname>div>a,.gl3t>a").forEach(a => a.setAttribute("target", "_blank")); break; @@ -74,4 +101,4 @@ mode: GM_getValue("exhtp.mode", "legacy"), views: GM_getValue("exhtp.views", "m"), newtab: GM_getValue("exhtp.newtab", true) -}); \ No newline at end of file +}); diff --git a/src/style.css b/src/style.css index 98a1d1b..fcc3fc4 100644 --- a/src/style.css +++ b/src/style.css @@ -1,9 +1,4 @@ -fieldset { - margin-bottom: 5px; - border-color: inherit; - border-style: solid; - border-width: 1px; -} +/* themes for e-h/exh */ .ehstyle { --bdc: #5c0d11; --bdca: #5c0d1199; @@ -18,16 +13,28 @@ fieldset { background-color: var(--bgc); border: 1px solid var(--bdc); } + +/* icon and tooltip positioning rules */ .glname { display: flex; + justify-content: space-between; } -.glname > svg { +.svgicon { align-self: center; cursor: pointer; - height: 24px; - margin-left: auto; padding-left: 8px; - width: auto; +} +.gl3m > .svgicon { + height: 20px; + min-width: 20px; +} +.gl3c > .svgicon { + height: 24px; + min-width: 24px; +} +.gl6t > .svgicon { + height: 16px; + min-width: 16px; } #tagstt { --l: initial; @@ -42,6 +49,8 @@ fieldset { visibility: var(--v); z-index: 100; } + +/* option button and panel */ .ttoptb { bottom: 0; cursor: pointer; @@ -82,6 +91,12 @@ fieldset { margin-left: 95%; text-decoration: none; } +#ttopt fieldset { + margin-bottom: 5px; + border-color: inherit; + border-style: solid; + border-width: 1px; +} #ttopt label { display: block; } diff --git a/src/tooltip.html b/src/tooltip.html index 333d41b..439c4e8 100644 --- a/src/tooltip.html +++ b/src/tooltip.html @@ -1 +1 @@ -
+