// ==UserScript==
// @name Sheezy_HoverPreview
// @namespace http://phi.pf-control.de
// @version 2024-04-03
// @description Shows various information when holding shift and hovering!
// @author dediggefedde
// @match https://sheezy.art/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=sheezy.art
// @grant GM.xmlHttpRequest
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
let els;
let headerHeight=0;
const map1 = new Map();
function getComment(link){
return new Promise((resolve, reject) =>{
if(map1.has(link))return resolve(map1.get(link));
GM.xmlHttpRequest({
method: "GET",
url: link,
onerror: function(response) {
reject({type:"failed comment request",url:link,content:response});
},
onload: async function(response) {
try{
const rex=/<div class="[^"]*? prose[^"]*?">([\r\n.\s\S]*?)<\/div>/i;
const res=response.response.match(rex);
if(res==null)return reject({type:"no comment match",content:response});
map1.set(link,res[1]);
return resolve(res[1]);
}catch(ex){
reject(reject({type:"unknown comment error",content:ex}));
}
}
});
});
}
function getSubmission(link){
return new Promise((resolve, reject) =>{
if(map1.has(link))return resolve(map1.get(link));
GM.xmlHttpRequest({
method: "GET",
url: link,
onerror: function(response) {
reject({type:"failed submission request",url:link,content:response});
},
onload: async function(response) {
try{
let rex=/<div [^>]*?id="artwork">([\r\n.\s\S]*?)<\/div>/i;
let res;
if(response.response.includes("/page-graphics/sheemz-422-by-majestea.webp")){
res="No Preview for mature content";
map1.set(link,res);
return resolve(res);
}
res=response.response.match(rex);
if(res==null)return reject({type:"no submission match",content:response});
map1.set(link,res[1]);
return resolve(res[1]);
}catch(ex){
reject(reject({type:"unknown submission error",content:ex}));
}
}
});
});
}
function getUploadLimit(){
return new Promise((resolve, reject) =>{
GM.xmlHttpRequest({
method: "GET",
url: "https://sheezy.art/upload/artwork",
onerror: function(response) {
reject({type:"failed upload limit request",content:response});
},
onload: async function(response) {
try{
let rex=/(You can .*?)(So far .*?\.)/i;
let res=response.response.match(rex);
if(res!=null)return resolve(`<p>${res[1]}</p><p>${res[2]}</p>`);
rex=/(You will be able [\r\n.\s\S]*?)<\//i;
res=response.response.match(rex);
if(res!=null)return resolve(`<p>${res[1]}</p>`);
if(res==null)return reject({type:"no limit match",content:response});
}catch(ex){
reject(reject({type:"unknown upload limit error",content:ex}));
}
}
});
});
}
function getInboxDetails(){
return new Promise((resolve, reject) =>{
GM.xmlHttpRequest({
method: "GET",
url: "https://sheezy.art/inbox?infinite=true&page=10&_data=routes/_frontend/_private/inbox/_index/_index",
onerror: function(response) {
reject({type:"failed upload inbox details request",content:response});
},
onload: async function(response) {
try{
const res=JSON.parse(response.response);
const namMap=new Map();
const typMap=new Map();
res.artworks.forEach(el=>{
const nam=el.userData.display_name;
if(namMap.has(nam)){
namMap.set(nam,namMap.get(nam)+1);
}else{
namMap.set(nam,1);
}
const typ=el.type;
if(typMap.has(typ)){
typMap.set(typ,typMap.get(typ)+1);
}else{
typMap.set(typ,1);
}
});
let resStr="";
if(namMap.size>0){
namMap.forEach((val,key,map)=>{
resStr+=`${val} from ${key}, `;
});
resStr=resStr.substring(0,resStr.length-2);
resStr+="<br/>There are "
typMap.forEach((val,key,map)=>{
resStr+=`${val} ${key}, `;
});
resStr=resStr.substring(0,resStr.length-2);
}
return resolve(`Your inbox has ${res.artworks.length} artwork entries.<br/>${resStr}.`);
}catch(ex){
reject(reject({type:"unknown Inbox Details error",content:ex}));
}
}
});
});
}
function getInboxSummary(){
return new Promise((resolve, reject) =>{
GM.xmlHttpRequest({
method: "GET",
url: "https://sheezy.art/inbox?infinite=true&page=1&_data=routes/_frontend/_private/inbox/_layout",
onerror: function(response) {
reject({type:"failed upload inbox request",content:response});
},
onload: async function(response) {
try{
const res=response.response;
const coms=res.match(/"comment":(\d+)/)[1];
const fols=res.match(/"followed":(\d+)/)[1];
const liks=res.match(/"like":(\d+)/)[1];
const reps=res.match(/"reply":(\d+)/)[1];
const journ=res.match(/"unseen_journals":(\d+)/)[1];
const arts=res.match(/"unseen_artworks":(\d+)/)[1];
const oths=res.match(/"unseen":\{(.*?)\}/)[1];
getInboxDetails().then(rest=>{
resolve(`Notifications:<br/>Comments: ${coms}, Replies: ${reps}, Like: ${liks}, Followed: ${fols}<br/><br/>New:<br/>Unseen Journals: ${journ}, Unseen Artworks: ${arts}, Unseen others: ${oths}<br/><br/>${rest}`);
});
}catch(ex){
reject(reject({type:"unknown Inbox error",content:ex}));
}
}
});
});
}
function getProfile(link){
return new Promise((resolve, reject) =>{
GM.xmlHttpRequest({
method: "GET",
url: link,
onerror: function(response) {
reject({type:"failed upload limit request",content:response});
},
onload: async function(response) {
try{
let el=document.createElement("div");
el.innerHTML=response.response;
return resolve(el.querySelector("ul a[href*='/gallery/']").parentNode.parentNode.parentNode.innerHTML);
}catch(ex){
reject(reject({type:"unknown Profile error",content:ex}));
}
}
});
});
}
function shiftIntoView(){
const view={height:(window.innerHeight || document.documentElement.clientHeight),
width:(window.innerWidth || document.documentElement.clientWidth)};
let pos=els.getBoundingClientRect();
//scale to viewpower (half)
if(pos.height > view.height) els.style.width=pos.width*(view.height/pos.height)+"px";
if(pos.width > view.width) els.style.width=view.width+"px";
//shift into viewport (from bottom/right)
pos=els.getBoundingClientRect();
if(pos.bottom > view.height) els.style.top=(els.offsetTop+view.height-pos.bottom)+"px";
if(pos.right > view.width) els.style.left=(els.offsetLeft+view.width-pos.right)+"px";
}
function showHover(position,content,url){
els.innerHTML=`<header><a href=${url} SHP_hover="1">${url.replace("https://sheezy.art/","")}</a><button onclick='(()=>{document.getElementById("SHP_message_cont").style.display="none";})()'>Close</button></header>`+content;
els.style.left=(position.left+window.scrollX)+"px";
els.style.top=(position.top+position.height+window.scrollY)+"px";
els.style.height=els.style.width="";
els.style.display="block";
shiftIntoView();
}
function callForHover(ev,callback){
if (!ev.shiftKey)return;
const pos=ev.target.getBoundingClientRect();
ev.target.classList.add("SHP_waiting");
els.setAttribute("pendingPromise",ev.target.href);
callback(ev.target.href).then(com=>{
if(els.getAttribute("pendingPromise")==ev.target.href)showHover(pos,com,ev.target.href);
}).catch(ex=>{
console.log("Sheezy_HoverPreview error", ex);
}).finally(res=>{
ev.target.classList.remove("SHP_waiting");
});;
}
function init(){
if(document.getElementById("SHP_message_cont")==null){
GM_addStyle(`
#SHP_message_cont{
position:absolute;
width:66rem;
display:none;
padding:15px;
font-size:12pt;
background-color:rgb(var(--theme-sheezy-320) / var(--tw-bg-opacity));
border:2px solid rgb(var(--theme-sheezy-330));
overflow:hidden;
z-index:99999;
}
#SHP_message_cont header{
display:flex;
border-bottom:1px solid;
margin-bottom:5px;
}
#SHP_message_cont header a{flex:1;}
#SHP_message_cont header button{}
.SHP_waiting{
cursor:progress!important;
}
`);
els=document.createElement("div");
els.id="SHP_message_cont";
document.body.appendChild(els);
els.addEventListener("mouseenter",(ev)=>{
els.style.display="block";
});
els.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
});
els.addEventListener("load",(ev)=>{
shiftIntoView();
});
headerHeight=document.querySelector("#root>header").getBoundingClientRect().height;
//const observer = new MutationObserver(shiftIntoView);
//observer.observe(els,{ childList: true });
}
shiftIntoView();
const comments=document.querySelectorAll("a[href*='/comment/']:not([SHP_hover])");
comments.forEach(link=>{
link.setAttribute("SHP_hover","1");
link.addEventListener("mouseenter",(ev)=>{
callForHover(ev,getComment);
},false);
link.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
},false);
});
const submissions=document.querySelectorAll("a[href*='/gallery/']:not([SHP_hover])");
submissions.forEach(link=>{
link.setAttribute("SHP_hover","1");
link.addEventListener("mouseenter",(ev)=>{
callForHover(ev,getSubmission);
},false);
link.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
},false);
});
const uploadLink=document.querySelectorAll("a[href*='/upload/artwork']:not([SHP_hover])");
uploadLink.forEach(link=>{
link.setAttribute("SHP_hover","1");
link.addEventListener("mouseenter",(ev)=>{
callForHover(ev,getUploadLimit);
},false);
link.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
},false);
});
const inboxLink=document.querySelectorAll("a[href*='/inbox/notifications']:not([SHP_hover])");
inboxLink.forEach(link=>{
link.setAttribute("SHP_hover","1");
link.addEventListener("mouseenter",(ev)=>{
callForHover(ev,getInboxSummary);
},false);
link.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
},false);
});
const profileLink=document.querySelectorAll("a[title^='@']:not([SHP_hover])");
profileLink.forEach(link=>{
link.setAttribute("SHP_hover","1");
link.addEventListener("mouseenter",(ev)=>{
callForHover(ev,getProfile);
},false);
link.addEventListener("mouseleave",(ev)=>{
els.style.display="none";
},false);
});
}
setInterval(init,1000);
})();