您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
E-H Visited, combined with ExVisited, and then better.
当前为
// ==UserScript== // @name EhxVisited // @namespace https://sleazyfork.org/en/users/285675-hauffen // @version 2.33 // @description E-H Visited, combined with ExVisited, and then better. // @author Hauffen // @match https://javascript.info/indexeddb // @require https://code.jquery.com/jquery-3.3.1.min.js // @include /https?:\/\/(e-|ex)hentai\.org\/.*/ // ==/UserScript== (function() { window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; if (!window.indexedDB) { console.warn("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available."); return; } /*═════════════════════════════╗ ║ Configuration Defaults ║ ╚═════════════════════════════*/ var setStore = JSON.parse(localStorage.getItem("ehx-settings")) ? JSON.parse(localStorage.getItem("ehx-settings")) : JSON.parse('{"softHide":false, "minAdd":true, "minShow":false, "cssTT":false, "repPub":false, "cusCSS":true, "visHide":false, "hidShow":false, "pFilter":false, "pLimit":0, "stFilter":false, "stLimit":0}'); var filters = localStorage.getItem("ehx-filters") ? localStorage.getItem("ehx-filters") : "#\\[Erocolor\\]"; var cssV = localStorage.getItem("ehx-cssv") ? localStorage.getItem("ehx-cssv") : "box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;"; var cssH = localStorage.getItem("ehx-cssh") ? localStorage.getItem("ehx-cssh") : "box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;"; var cssD = (setStore.softHide) ? "opacity:0.2; -webkit-opacity: 0.2;" : "display: none;"; /*════════════════════════════*/ let db = null; var filterArr = []; if (!setStore.cusCSS) { cssV = ""; cssH = ""; } var pIS = 0; var observer = new MutationObserver(e => { pIS = true; addCSS(); }); var spl = document.URL.split("/"); var d1 = spl[3]; var sto = '{"data":{}}'; var galleries = JSON.parse(sto); var hidden = JSON.parse(sto); var ehxClearConfirm = 0; if (spl[3] == "g") addGallery(); if (d1.substr(0, 1) == "?" || d1.substr(0, 1) == "#" || d1.substr(0, 1) == "f" || d1.substr(0, 1) == "t" || !d1) { popFilter(filters); populate(); } function popFilter() { if (filters != "") { var tempArr = filters.split("\n"); for(var i = 0; i < tempArr.length; i++) { if (tempArr[i].startsWith("#")) continue; filterArr.push(new RegExp(tempArr[i], "i")); } } } function addGallery() { const request = indexedDB.open("ehxvisited", 1); request.onupgradeneeded = e => { // Generate our database if it's not there db = e.target.result; if (!db.objectStoreNames.contains('galleries')) { db.createObjectStore('galleries', {keyPath: 'id'}); } if (!db.objectStoreNames.contains('hidden')) { db.createObjectStore('hidden', {keyPath: 'id'}); } }; request.onsuccess = e => { db = e.target.result; var objStore = db.transaction('galleries', 'readwrite').objectStore('galleries'); var openRequest = objStore.openCursor(spl[4] + "." + spl[5]); openRequest.onsuccess = e => { var cursor = openRequest.result; if (cursor) { // Update entry if key exists cursor.update({id: spl[4] + "." + spl[5], visited: Date.now()}); console.log("EhxVisited: Updated " + spl[4] + "." + spl[5]); } else { // Otherwise, add entry objStore.add({id: spl[4] + "." + spl[5], visited: Date.now()}); console.log("EhxVisited: Added " + spl[4] + "." + spl[5]); } }; openRequest.onerror = e => { console.log(`EhxVisited: Something bad happened with gallery ${spl[4]}.${spl[5]}: ${e.target.error}`); }; }; }; function updateGListing() { var list = $(".itg .gl1t").length > 0 ? $(".itg .gl1t") : $("table.itg>tbody>tr").has('.glhide, .gldown, th'); var hAmount, vAmount, fAmount, pAmount, rAmount, hCount; hAmount = vAmount = fAmount = pAmount = rAmount = hCount = 0; for (var i = 0; i < list.length; i++) { if ($(list[i]).hasClass("ehx-hidden")) { if ($(list[i]).hasClass("ehx-visited")) vAmount++; hCount++; } if ($(list[i]).attr("data-jqstyle") != undefined) { if ($(list[i]).attr("data-jqstyle").match('h')) hAmount++; if ($(list[i]).attr("data-jqstyle").match('f')) fAmount++; if ($(list[i]).attr("data-jqstyle").match('p')) pAmount++; if ($(list[i]).attr("data-jqstyle").match('r')) rAmount++; } if($(".ehx-show").text() === "Show") { if ($(list[i]).hasClass("ehx-visited")) { vAmount++; hCount++; } } } if(!setStore.softHide) { $("#hideCount").html("There " + (hCount > 1 || hCount == 0 ? 'are ' : 'is ') + "<span>" + hCount + " hidden " + (hCount > 1 || hCount == 0 ? 'galleries' : 'gallery') + "</span> on this page."); } else { $("#hideCount").html("There are <span>0 hidden galleries</span> on this page."); } $("#hideCount > span").prop("title", "Hidden: " + hAmount + " | Visited: " + vAmount + " | Filtered: " + fAmount + " | Page Limit: " + pAmount + " | Rating Limit: " + rAmount); } // Convert star count to integer function getStarNumber(el) { var stars = $(el).find(".ir").css("background-position"); switch(stars) { case "0px -1px": return 5; case "0px -21px": return 4.5; case "-16px -1px": return 4; case "-16px -21px": return 3.5; case "-32px -1px": return 3; case "-32px -21px": return 2.5; case "-48px -1px": return 2; case "-48px -21px": return 1.5; case "-64px -1px": return 1; case "-64px -21px": return 0.5; default: return 0; } } // Check elements through the filters, page filtering would be in here if it didn't have page counts in every random element function filterCheck(el) { if (filterArr.length > 0) { if(filterArr.some(rx => rx.test($(el).find('.glink').text()))) { if(!$(el).hasClass('ehx-hidden')) { $(el).addClass("ehx-hidden"); } addStyle($(el), "f"); } } if (setStore.stFilter && setStore.stLimit > 0) { if (getStarNumber(el) < setStore.stLimit) { if(!$(el).hasClass('ehx-hidden')) { $(el).addClass("ehx-hidden"); } addStyle($(el), "r"); } } } function addStyle(el, flag) { if ($(el).attr("data-jqstyle") != undefined) { $(el).attr("data-jqstyle", $(el).attr("data-jqstyle") + flag); } else { $(el).attr("data-jqstyle", flag); } } function removeStyle(el, flag) { if ($(el).attr("data-jqstyle") != undefined) { $(el).attr("data-jqstyle", $(el).attr("data-jqstyle").replace(flag, '')); } else { $(el).attr("data-jqstyle", ""); } } function toggleElement(tga, el, list) { const request = indexedDB.open("ehxvisited", 1); var tgid = tga.split('/')[4] + "." + tga.split('/')[5]; request.onsuccess = e => { db = e.target.result; var objStore = db.transaction("hidden", "readwrite").objectStore("hidden"); var openReq = objStore.openCursor(tgid); openReq.onsuccess = e => { var cursor = e.target.result; if (cursor) { cursor.delete(); console.log("EhxVisited: Removed " + tgid + " from hidden list."); $(el).removeClass("ehx-hidden"); removeStyle($(el), "h"); delete hidden.data[tgid]; } else { objStore.put({id: tgid}); console.log("EhxVisited: Added " + tgid + " to hidden list."); $(el).addClass("ehx-hidden"); addStyle($(el), "h"); hidden.data[tgid] = 1; } updateGListing(); $("#hLength").text(Object.keys(hidden.data).length); } } } function populate() { const request = indexedDB.open("ehxvisited", 1); request.onupgradeneeded = e => { db = e.target.result; if (!db.objectStoreNames.contains('galleries')) { db.createObjectStore('galleries', {keyPath: 'id'}); } if (!db.objectStoreNames.contains('hidden')) { db.createObjectStore('hidden', {keyPath: 'id'}); } }; request.onsuccess = e => { db = e.target.result; var objStore = db.transaction("galleries", "readonly").objectStore("galleries"); var openReq = objStore.getAll(); openReq.onsuccess = f => { console.log("EhxVisited: Populated global variables."); var transform = f.target.result; for (var i = 0; i < transform.length; i++) { galleries.data[transform[i].id] = transform[i].visited; // Force matrix data into array data } var gLength = Object.keys(galleries.data).length var objStore2 = db.transaction("hidden", "readonly").objectStore("hidden"); var openReq2 = objStore2.getAll(); openReq2.onsuccess = g => { var transform2 = g.target.result; for (i = 0; i < transform2.length; i++) { hidden.data[transform2[i].id] = 1; // Force matrix data into array data } var hLength = Object.keys(hidden.data).length $("#toppane").append("<ehx class='ehx-controls'>Galleries visited: <span id='gLength'>" + gLength + "</span> ( <span id='ehx-menu-control'></span><a href='javascript:;' class='ehx-settings'>Settings</a> )<br/>Hidden Galleries: <span id='hLength'>" + hLength + "</span><span id='ehxh-menu-control'></span></ehx>"); if (!setStore.softHide) { $("#ehx-menu-control").append("<a href='javascript:;' class='ehx-show'>Hide</a> / "); $("#ehxh-menu-control").append(" ( <a href='javascript:;' class='ehxh-show'>Show</a> )"); } $(".ehx-settings").click(e => { e.preventDefault(); settings(); return false; }); $(".ehx-show").click(e => { var disp = $(".ehx-visited.ehx-hidden").css("display"); if ($(".ehx-show").text() === "Show") { $(".ehx-visited").css({display: ""}); $(".ehx-visited.ehx-hidden").css({display: disp}); } else { $(".ehx-visited").css({display: "none"}); $(".ehx-visited.ehx-hidden").css({display: disp}); } $(".ehx-show").text((i, t) => { return t === "Show" ? "Hide" : "Show"; }); updateGListing(); setStore.visHide = $(".ehx-show")[0].innerText === "Show" ? true : false; localStorage.setItem("ehx-settings", JSON.stringify(setStore)); }); $(".ehxh-show").click(e => { if ($(".ehxh-show").text() === "Show") { if ($(".gl1t").length == 0) { $(".ehx-hidden").css({display: $(".ehx-hidden").parent().find("tr").not(".ehx-hidden").css("display")}); $(".ehx-visited.ehx-hidden").css({display: $(".ehx-hidden").parent().find("tr").not(".ehx-hidden").css("display")}); } else { $(".ehx-hidden").css({display: 'flex'}); $(".ehx-visited.ehx-hidden").css({display: 'flex'}); } } else { $(".ehx-hidden").css({display: ""}); $(".ehx-visited.ehx-hidden").css({display: ""}); } $(".ehxh-show").text((i, t) => { return t === "Show" ? "Hide" : "Show"; }); updateGListing(); setStore.hidShow = $(".ehxh-show")[0].innerText === "Hide" ? true : false; localStorage.setItem("ehx-settings", JSON.stringify(setStore)); }); addCSS(); $(".ehx-controls").append("<br /><span id='hideCount'><span></span></span>"); updateGListing(); } } } } function addCSS() { observer.disconnect(); // Disconnect the observer, or else all the CSS changes will trigger the mutation observer var img_hide = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIhSURBVDjLlZPrThNRFIWJicmJz6BWiYbIkYDEG0JbBiitDQgm0PuFXqSAtKXtpE2hNuoPTXwSnwtExd6w0pl2OtPlrphKLSXhx07OZM769qy19wwAGLhM1ddC184+d18QMzoq3lfsD3LZ7Y3XbE5DL6Atzuyilc5Ciyd7IHVfgNcDYTQ2tvDr5crn6uLSvX+Av2Lk36FFpSVENDe3OxDZu8apO5rROJDLo30+Nlvj5RnTlVNAKs1aCVFr7b4BPn6Cls21AWgEQlz2+Dl1h7IdA+i97A/geP65WhbmrnZZ0GIJpr6OqZqYAd5/gJpKox4Mg7pD2YoC2b0/54rJQuJZdm6Izcgma4TW1WZ0h+y8BfbyJMwBmSxkjw+VObNanp5h/adwGhaTXF4NWbLj9gEONyCmUZmd10pGgf1/vwcgOT3tUQE0DdicwIod2EmSbwsKE1P8QoDkcHPJ5YESjgBJkYQpIEZ2KEB51Y6y3ojvY+P8XEDN7uKS0w0ltA7QGCWHCxSWWpwyaCeLy0BkA7UXyyg8fIzDoWHeBaDN4tQdSvAVdU1Aok+nsNTipIEVnkywo/FHatVkBoIhnFisOBoZxcGtQd4B0GYJNZsDSiAEadUBCkstPtN3Avs2Msa+Dt9XfxoFSNYF/Bh9gP0bOqHLAm2WUF1YQskwrVFYPWkf3h1iXwbvqGfFPSGW9Eah8HSS9fuZDnS32f71m8KFY7xs/QZyu6TH2+2+FAAAAABJRU5ErkJggg=="; var list = $("table.itg>tbody>tr").has('.glhide, .gldown, th'); // Present only in list views var thumb = $(".itg .gl1t"); // Present only in thumbnail view var gid, galleryId, onFavs, d; if (list.length > 0) { if ($('.gl1e').length) { // Extended if ($('h1').text() === "Favorites") { onFavs = 1; } for (var i = 0; i < list.length; i++) { gid = $(list[i]).find(".gl1e a").attr("href").split("/"); galleryId = gid[4] + "." + gid[5]; if ($(list[i])[0].children.length === 2 && onFavs) { $(list[i]).append('<td></td>'); } if(galleries.data[galleryId] != undefined) { if (!$(list[i]).hasClass('ehx-visited')) { d = new Date(galleries.data[galleryId]); $(list[i]).addClass("ehx-visited"); if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate()); // Check for fav pages if ($(list[i]).find('.gl3e').children('div').length >= 7) { // Date favourited div is present $(list[i]).find('.gl3e > div:last-child').append("<br><ehx class='ehx-extended-favs'>\uD83D\uDC41" + timeDifference(Date.now(), galleries.data[galleryId]) + "<br>" + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ")</ehx>"); } else { $(list[i]).find('.gl3e').append("<ehx class='ehx-extended'>\uD83D\uDC41" + timeDifference(Date.now(), galleries.data[galleryId]) + "<br>" + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ")</ehx>"); } } } else { if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited"); } if(hidden.data[galleryId] != undefined) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "h"); } if($(list[i])[0].childElementCount < 3) { $("<img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; padding:4px 0px 0px 4px;' title='Show/Hide gallery'>").prependTo($(list[i]).find("a").first().parent().parent().parent()).on('click', e => { var el = $(e.currentTarget).parent(); toggleElement($(el).find("a").attr("href"), $(el), list); }) } if (setStore.pFilter && setStore.pLimit > 0) { if(parseInt($(list[i]).find('.gl3e > div:nth-child(5)').text().split(" ")[0]) < parseInt(setStore.pLimit)) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "p"); } } filterCheck($(list[i])); } updateGListing(); } else if ($('.gl1c').length) { // Compact var borderColour = $('.gl1c').first().css('border-top-color'); // Border colour is different between domains if (!pIS && $('table.itg tbody>tr:first-child')[0].children.length < 5) { $('table.itg tbody>tr:first-child th:nth-child(4)').after('<th style="text-align:center;" title="EhxVisited: Click to Show/Hide">✖</th>'); $('table.itg tbody>tr:first-child th:nth-child(2)').after('<th>Visited</th>'); pIS = true; } if ($('h1').text() === "Favorites") { onFavs = 1; } for (i = 1; i < list.length; i++) { gid = $(list[i]).find(".glname a").attr("href").split("/"); galleryId = gid[4] + "." + gid[5]; if ($(list[i])[0].children.length === 4 || $(list[i])[0].children.length === 5 && onFavs) { if ($(list[i])[0].children.length === 4 && onFavs) { $(list[i]).append('<td></td>'); } if(galleries.data[galleryId] != undefined) { d = new Date(galleries.data[galleryId]); $(list[i]).addClass("ehx-visited"); if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate()); $(list[i]).children('.gl2c').after('<td class="ehx-compact" style="border-color:' + borderColour + ';"><ehx>' + timeDifference(Date.now(), galleries.data[galleryId], true) + "<br>(" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ')<br>' + d.getFullYear().toString().substr(2) + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '</ehx></td>'); } else { if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited"); $(list[i]).children('.gl2c').after('<td class="ehx-compact" style="border-color:' + borderColour + ';"></td>'); } } if(hidden.data[galleryId] != undefined) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "h"); } if($(list[i])[0].childElementCount < 6) { $("<td class='hideContainer' style='border-bottom: 1px solid #6f6f6f4d; border-top: 1px solid #6f6f6f4d;'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; vertical-align:center;' title='Show/Hide gallery'></td>").appendTo($(list[i]).find("a").first().closest("tr")).on('click', e => { var el = $(e.currentTarget).closest("tr"); toggleElement($(el).find($(".gl3c>a")).attr("href"), $(el), list); }) } if (setStore.pFilter && setStore.pLimit > 0) { // Filter out based on page count if(parseInt($(list[i]).find('.gl4c > div:nth-child(2)').text().split(" ")[0]) < parseInt(setStore.pLimit)) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "p"); } } filterCheck($(list[i])); } updateGListing(); } else { // Minimal if(!pIS) { $('table.itg tbody>tr:first-child th:nth-child(6)').after('<th style="text-align:center;" title="EhxVisited: Click to Show/Hide">✖</th>'); if (setStore.minAdd) { $('table.itg tbody>tr:first-child th:nth-child(2)').after('<th title="EhxVisited: Hover for timestamps">\uD83D\uDC41</th>'); } pIS = true; } if (setStore.repPub) { $('table.itg tbody>tr:first-child')[0].children[1].innerText = "Visited" } if ($('h1').text() === "Favorites") { onFavs = 1; } for (i = 1; i < list.length; i++) { gid = $(list[i]).find(".glname a").attr("href").split("/"); galleryId = gid[4] + "." + gid[5]; if(hidden.data[galleryId] != undefined) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "h"); } if ($(list[i])[0].children.length === 6 || $(list[i])[0].children.length === 7 && onFavs) { if ($(list[i])[0].children.length === 6 && onFavs) { $(list[i]).append('<td></td>'); } if (setStore.minAdd) { // Append viewed column if (galleries.data[galleryId] != undefined) { d = new Date(galleries.data[galleryId]); $(list[i]).addClass("ehx-visited"); if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate()); if (setStore.minShow) { // Show text in appended column $(list[i]).children('.gl2m').after('<td class="ehx-minimal-text"><ehx>' + timeDifference(Date.now(), galleries.data[galleryId], true) + "<br>(" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ')<br>' + d.getFullYear().toString().substr(2) + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '</ehx></td>'); } else { // Show icon in appended column $(list[i]).children('.gl2m').after('<td class="ehx-minimal" title="EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '"><ehx>\uD83D\uDC41</ehx></td>'); } if (setStore.repPub) { $(list[i]).find(".gl2m").text(d.getFullYear().toString() + "\u2011" + ('0' + (d.getMonth() + 1)).slice(-2) + "\u2011" + d.getDate() + " " + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0')); } } else { // Not viewed $(list[i]).children('.gl2m').after('<td class="ehx-minimal"></td>'); // Only append another table cell to the row if (setStore.repPub) $(list[i]).find(".gl2m").text("Never Visited"); if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited"); } } else { // Append nothing, highlight only if (galleries.data[galleryId] != undefined) { d = new Date(galleries.data[galleryId]); $(list[i]).addClass("ehx-visited"); $(list[i]).children('.glname')[0].setAttribute("title", 'EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate()); } } if($(list[i])[0].childElementCount < 8 || ($(list[i])[0].childElementCount < 8 && !setStore.minAdd)) { $("<td class='hideContainer'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; vertical-align:middle;' title='Show/Hide gallery'></td>").appendTo($(list[i]).find("a").first().closest("tr")).on('click', e => { var el = $(e.currentTarget).closest("tr"); toggleElement($(el).find($(".gl3m>a")).attr("href"), $(el), list); }) } if (setStore.pFilter && setStore.pLimit > 0) { // Filter out based on page count if(parseInt($(list[i]).find('.gl2m > div:nth-child(2) > div:nth-child(2) > div:nth-child(2) > div:nth-child(2)').text().split(" ")[0]) < parseInt(setStore.pLimit)) { if(!$(list[i]).hasClass('ehx-hidden')) { $(list[i]).addClass("ehx-hidden"); } addStyle($(list[i]), "p"); } } filterCheck($(list[i])); } } updateGListing(); } } else if (thumb.length > 0) { // Thumbnail for (i = 0; i < thumb.length; i++) { gid = $(thumb[i]).find(".gl3t a").attr("href").split("/"); galleryId = gid[4] + "." + gid[5]; if(galleries.data[galleryId] != undefined) { if (!$(thumb[i]).hasClass('ehx-visited')) { d = new Date(galleries.data[galleryId]); $(thumb[i]).addClass("ehx-visited"); if (setStore.cssTT) { $(thumb[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate()); } $(thumb[i]).children('.gl5t').after("<ehx class='ehx-thumbnail'>\uD83D\uDC41" + timeDifference(Date.now(), galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + "</ehx>"); } } else { if (setStore.cssTT) { $(thumb[i]).find('.glname').attr("title", "Never Visited"); } } if(hidden.data[galleryId] != undefined) { if(!$(thumb[i]).hasClass('ehx-hidden')) { $(thumb[i]).addClass("ehx-hidden"); } addStyle($(thumb[i]), "h"); } if($(thumb[i]).find(".gl5t").children().length < 3) { // Append X button $("<div class='hideContainer'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; position:absolute; bottom:3px; left:2px;' title='Show/Hide gallery'></div>").appendTo($(thumb[i]).find(".gl5t")).on('click', e => { var el = $(e.currentTarget).parent().parent(); toggleElement($(el).find("a").attr("href"), $(el), thumb); }) } if (setStore.pFilter && setStore.pLimit > 0) { // Filter out based on page count if(parseInt($(thumb[i]).find('.gl5t > div:nth-child(2) > div:nth-child(2)').text().split(" ")[0]) < parseInt(setStore.pLimit)) { if(!$(thumb[i]).hasClass('ehx-hidden')) { $(thumb[i]).addClass("ehx-hidden"); } addStyle($(thumb[i]), "p"); } } filterCheck($(thumb[i])); } updateGListing(); } else { console.log("EhxVisited: Something went wrong or an invalid view"); } if (setStore.visHide) { $(".ehx-visited").css({display: "none"}); // Change this probably $(".ehx-show").text("Show"); } if (setStore.hidShow) { if ($(".ehx-hidden").length < 25) { $(".ehx-hidden").css({display: $(".ehx-hidden").siblings().not(".ehx-hidden").css("display")}) } else { if ($(".gl1t").length > 0) { $(".ehx-hidden").css({display: "flex"}); } else { $(".ehx-hidden").css({display: "table-row"}); } } $(".ehxh-show").text("Hide"); } observer.observe($('.itg').get(0), { // Reconnect the observer for changes childList: true, subtree: true }); } // Get time difference in words function timeDifference(current, previous, abbreviate) { var msPerMinute = 60 * 1000; var msPerHour = msPerMinute * 60; var msPerDay = msPerHour * 24; var msPerMonth = msPerDay * 30; var msPerYear = msPerDay * 365; var elapsed = current - previous; if (elapsed < msPerMinute) { return Math.round(elapsed / 1000) + ((typeof abbreviate !== 'undefined') ? ' sec' : ' seconds ago'); } else if (elapsed < msPerHour) { return Math.round(elapsed / msPerMinute) + ((typeof abbreviate !== 'undefined') ? ' min' : ' minutes ago'); } else if (elapsed < msPerDay) { return Math.round(elapsed / msPerHour) + ((typeof abbreviate !== 'undefined') ? ' hrs' : ' hours ago'); } else if (elapsed < msPerMonth) { return Math.round(elapsed / msPerDay) + ((typeof abbreviate !== 'undefined') ? ' days' : ' days ago'); } else if (elapsed < msPerYear) { return Math.round(elapsed / msPerMonth) + ((typeof abbreviate !== 'undefined') ? ' mos' : ' months ago'); } else { return Math.round(elapsed / msPerYear) + ((typeof abbreviate !== 'undefined') ? ' yrs' : ' years ago'); } } function ehxExport(message, items) { var data = ""; for (var i in items) { data += items[i].id + ":" + items[i].visited + ";"; } if ($('.ehx-exported-data').length) { // Remove any data if it exists for whatever reason $('.ehx-exported-data').remove(); } $('.section-container').prepend('<section class="ehx-exported-data"><fieldset><legend>' + message + '</legend><div><textarea class="ehx-exported-data-text">' + data + '</textarea></div></fieldset></section>'); } $(".itg").on("mousedown", "a", e => { if (e.currentTarget.href.split('/')[3] === "g") { galleries.data[e.currentTarget.href.split('/')[4] + "." + e.currentTarget.href.split('/')[5]] = Date.now(); $("#gLength").text(Object.keys(galleries.data).length); addCSS(); } }); // Open the Settings menu function settings() { const req = indexedDB.open("ehxvisited", 1); req.onsuccess = e => { if (db == null) db = e.target.result; var objStore = db.transaction('galleries', 'readwrite').objectStore('galleries'); var openReq = objStore.getAll(); openReq.onsuccess = e => { var len = e.target.result; // There's probably a much easier way to do this, or at least a nicer looking, more technical way var container = $(`<div class="overlay"><div class="settings"><nav class="topNav"> <span style="float:left;margin-left:3px;font-weight:lighter;opacity:0.5;-webkit-opacity:0.5;">All Settings Will Be Applied On Close</span> <div><a id="ehx-export" href="javascript:;">Export</a> | <a id="ehx-import" href="javascript:;">Import</a> | <a id="settings-close" href="javascript:;">🞫</a></div> </nav><div class="section-container"><section><fieldset><legend>Settings</legend> <div><label><input type="checkbox" id="softHide" ` + (setStore.softHide ? `checked` : ``) + `>Soft Hide Galleries</label><span>: Darken hidden galleries instead of removing them from view</span></div> <div><label><input type="checkbox" id="minAdd" ` + (setStore.minAdd ? `checked` : ``) + `>Minimal Add Column</label><span>: Show visits in an additional column in Minimal/Minimal+ view modes</span> <div class="suboptions"><div><span class="branch">∟</span> <label><input type="checkbox" id="minShow" ` + (setStore.minShow ? `checked` : ``) + `>Minimal Show Text</label><span>: Show visits as text instead of hovering tooltip in Minimal/Minimal+ view modes</span></div></div></div> <div><label><input type="checkbox" id="cssTT" ` + (setStore.cssTT ? `checked` : ``) + `>CSS Tooltips</label><span>: Replace gallery link tooltips with visited information in all view modes</span></div> <div><label><input type="checkbox" id="repPub" ` + (setStore.repPub ? `checked` : ``) + `>Replace Published</label><span>: Replace date published with date visited in Minimal/Minimal+ view modes</span></div> </fieldset><fieldset><legend><label id="cCSS"><input type="checkbox" id="cusCSS" ` + (setStore.cusCSS ? `checked` : ``) + `>Custom CSS</label></legend> <h3>Visited Galleries :<div id="visControls"><button id="resV">Reset CSS</button><button class="ehx-clear">Clear Data</button></div></h3> <textarea id="visited" class="field" spellcheck="false" placeholder="box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;">` + cssV + `</textarea> <h3>Hidden Galleries :<div id="hideControls"><button id="resH">Reset CSS</button><button class="ehxh-clear">Clear Data</button></div></h3> <textarea id="hidden" class="field" spellcheck="false" placeholder="box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;">` + cssH + `</textarea> </fieldset><fieldset><legend>Filters</legend> Use one <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">regular expression</a> per line to filter out matching galleries.<ul style="margin: 3px 0px; padding-left: 30px;"> <li>E.G. <code>Ongoing</code> will filter out every gallery with <code>ongoing</code>, case-insensitive, in the title. <code>\\[Digital\\]</code> will filter out every gallery with <code>[Digital]</code>, case-insensitive, in the title.</li> <li>Lines starting with <code>#</code> will be ignored.</li></ul><textarea id="galFilter">` + filters + `</textarea> <div><label><input type="checkbox" id="pFilt" ` + (setStore.pFilter ? `checked` : ``) + `>Page Limit</label><span>: Filter out any gallery with pages below the page limit<input id="pLim" type="number" min="1" value="` + setStore.pLimit + `" ` + (setStore.pFilter ? `` : `disabled`) + `/></span></div> <div><label><input type="checkbox" id="stFilt" ` + (setStore.stFilter ? `checked` : ``) + `>Minimum Rating</label><span>: Filter out any gallery with a rating below the limit<select id="stLim" ` + (setStore.stFilter ? `` : `disabled`) + `> <option>5</option><option>4.5</option><option>4</option><option>3.5</option><option>3</option><option>2.5</option> <option>2</option><option>1.5</option><option>1</option><option>0.5</option><option>0</option></select></span> </div></div></fieldset></section></div></div></div>`); $("body").append(container); $(document).on("change", "input", e => { if ($("#minAdd").prop('checked')) { $("#minShow").prop("disabled", false); } else { $("#minShow").prop("disabled", true); } if ($("#cusCSS").prop("checked")) { $("#visited").prop("disabled", false); $("#hidden").prop("disabled", false); $("#resV").prop("disabled", false); $("#resH").prop("disabled", false); } else { $("#visited").prop("disabled", true); $("#hidden").prop("disabled", true); $("#resV").prop("disabled", true); $("#resH").prop("disabled", true); } if ($("#pFilt").prop('checked')) { $("#pLim").prop("disabled", false); } else { $("#pLim").prop("disabled", true); } if ($("#stFilt").prop('checked')) { $("#stLim").prop("disabled", false); } else { $("#stLim").prop("disabled", true); } }); $("#settings-close").click(e => { // Grab the settings and place them into our temporary variables var tempSto = { "softHide": $("#softHide").prop('checked'), "minAdd": $("#minAdd").prop('checked'), "minShow": $("#minShow").prop('checked'), "cssTT": $("#cssTT").prop('checked'), "repPub": $("#repPub").prop('checked'), "cusCSS": $("#cusCSS").prop('checked'), "visHide": $(".ehx-show").text() === "Show" ? true : false, "hidShow": $(".ehxh-show").text() === "Hide" ? true : false, "pFilter": $("#pFilt").prop('checked'), "pLimit": $("#pFilt").prop('checked') ? $("#pLim").val() : "0", "stFilter": $("#stFilt").prop('checked'), "stLimit": $("#stFilt").prop('checked') ? $("#stLim option:selected").text() : "0" } localStorage.setItem("ehx-settings", JSON.stringify(tempSto)); // Write settings to localStorage setStore = tempSto; localStorage.setItem("ehx-cssv", $("#visited").val()); localStorage.setItem("ehx-cssh", $("#hidden").val()); localStorage.setItem("ehx-filters", $("#galFilter").val()); if (setStore.softHide == true) { $("#ehx-menu-controls").css({display: ""}); $("#ehxh-menu-controls").css({display: ""}); } $(".overlay").remove(); location.reload(); // Force reload to apply settings }); $("#resV").click(e => { $("#visited").val("box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;"); }); // Default Values $("#resH").click(e => { $("#hidden").val("box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;"); }); // Default Values if (!$("#minAdd").prop("checked")) { $("#minShow").prop("disabled", true); } if (!$("#cusCSS").prop("checked")) { $("#visited").prop("disabled", true); $("#hidden").prop("disabled", true); $("#resV").prop("disabled", true); $("#resH").prop("disabled", true); } $("#stLim").val(setStore.stLimit); $("body").click(e => { if (e.target.className == "overlay") { // Exit if settings menu isn't clicked var tempSto = { "softHide": $("#softHide").prop('checked'), "minAdd": $("#minAdd").prop('checked'), "minShow": $("#minShow").prop('checked'), "cssTT": $("#cssTT").prop('checked'), "repPub": $("#repPub").prop('checked'), "cusCSS": $("#cusCSS").prop('checked'), "visHide": $(".ehx-show").text() === "Show" ? true : false, "hidShow": $(".ehxh-show").text() === "Hide" ? true : false, "pFilter": $("#pFilt").prop('checked'), "pLimit": $("#pFilt").prop('checked') ? $("#pLim").val() : "0", "stFilter": $("#stFilt").prop('checked'), "stLimit": $("#stFilt").prop('checked') ? $("#stLim option:selected").text() : "0" } localStorage.setItem("ehx-settings", JSON.stringify(tempSto)); // Write settings to localStorage setStore = tempSto; localStorage.setItem("ehx-cssv", $("#visited").val()); localStorage.setItem("ehx-cssh", $("#hidden").val()); localStorage.setItem("ehx-filters", $("#galFilter").val()); if (setStore.softHide == true) { $("#ehx-menu-controls").css({display: ""}); $("#ehxh-menu-controls").css({display: ""}); } $(".overlay").remove(); // Not entirely necessary, but slightly cosmetic location.reload(); // Force reload to apply settings } }); $("#ehx-import").click(e => { var objStore2 = db.transaction('galleries', 'readwrite').objectStore('galleries'); var c = prompt("EhxVisited:\nPaste here to import."); if (c) { var sp = c.split(";"); sp = sp.filter(Boolean); // Filter out any null ("") entries var count = 0; insertNext(); function insertNext() { if (count < sp.length) { var str = sp[count].split(":"); objStore2.put({id: str[0], visited: parseInt(str[1])}).onsuccess = insertNext; ++count; } else { console.log("EhxVisited: Merge Completed"); } } alert("EhxVisited:\nImported " + sp.length + " entries."); location.reload(); } }); $("#ehx-export").click(e => { ehxExport('Exported entries:', len); }); $(".ehx-clear").click(e => { if (!ehxClearConfirm) { // Make sure to double check before deleting ehxClearConfirm = 1; $('.ehx-clear').append(': Are you sure?'); ehxExport('Backup your current data:', len); } else { var objStore2 = db.transaction('galleries', 'readwrite').objectStore('galleries'); var openReq = objStore2.clear(); openReq.onsuccess = e => { alert("EhxVisited:\nCleared all entries."); location.reload(); } } }); $(".ehxh-clear").click(e => { // Delete hidden stuff without checking because it's not critical var objStore2 = db.transaction('hidden', 'readwrite').objectStore('hidden'); var openReq = objStore2.clear(); openReq.onsuccess = e => { alert("EhxVisited:\nCleared all entries."); location.reload(); } }); } } } // The giant CSS block var inheritFonts = $('body').css('font-family') + ', arial, symbola'; $(`<style data-jqstyle='ehxVisited'> ehx { font-family:` + inheritFonts + ` } .gl2c { width: 115px; } .ehx-visited .gl3e { min-height: 206px; } .ehx-visited .gl4e { min-height: 264px !important; } .ehx-hidden { ` + cssD + cssH + ` } .ehx-exported-data { display: block; } .ehx-minimal { border-left: 1px solid #6f6f6f4d;} .ehx-minimal-text { text-align: center; display: block; } .ehx-compact { border-style: solid; border-width: 1px 0; text-align: center; } .ehx-extended { width: 120px; position: absolute; left: 3px; top: 172px; text-align: center; font-size: 8pt; line-height: 1.5; } .ehx-extended-favs { padding: 3px 1px; display: block; line-height: 1.5; } .ehx-thumbnail { display: block; text-align: center; margin: 3px 0 5px; line-height: 12px; } .ehx-controls { padding: 3px 1px; text-align: center; display: block; } #hideCount > span { border-bottom: 1px dotted currentColor; } table.itg > tbody > tr.ehx-visited, .gl1t.ehx-visited { ` + cssV + ` } table.itg > tbody > tr.ehx-visited.ehx-hidden, .gl1t.ehx-visited.ehx-hidden { ` + cssH + ` } .overlay { background: rgba(0,0,0,0.5); display: -webkit-flex; display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index:999; font-size: 9pt; } .settings { background: ` + $(".ido").css("background") + `; box-sizing: border-box; height: 555px; max-height: 100%; width: 900px; max-width: 100%; margin: auto; padding: 5px; display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.5); } .settings nav { text-align: right; padding-bottom: 5px; font-weight: bold;} .settings legend { font-size: 10pt; font-weight: bold; } .settings label { font-weight: bold; text-decoration: underline; cursor: pointer; } .settings h3 { margin: 3px; position: relative; } .settings span { margin-left: -3px; } .settings input { vertical-align: -1px; } .settings textarea { width: 100%; height: 150px; resize: vertical; } .suboptions { position: relative; } .suboptions > div { position: relative; padding-left: 1.4em; } .branch { position: absolute; left: 10px; top: 1px; } .nav > div { text-align: right; } #settings-close, #cCSS { text-decoration: none; } #visControls, #hideControls { position: absolute; right: -5px; } #visControls { top: -6px; } #hideControls { top: -3px; } .section-container { text-align: left; overflow: auto;} .section-container textarea:disabled, .section-container input:disabled, .section-container select:disabled { opacity: 0.6; -webkit-opacity: 0.6; } .section-container input[type="number"] { border: 1px solid #8d8d8d; margin-left:15px; text-align: center; width: 50px;} .section-container select {margin-left: 15px; } .section-container code { color: #000; background-color: #FFF; } </style>`).appendTo("head"); })();