// ==UserScript==
// @name rendero-info
// @namespace what.ever
// @match https://www.renderosity.com/rr/mod/*
// @match https://www.renderotica.com/store/sku/*
// @grant GM_xmlhttpRequest
// @version 1.0
// @author -
// @description -
// ==/UserScript==
const W = 380;
const H = 494;
let info = null;
// get info
try {
if(location.host.includes('renderosity')){
info = {
store: 'Renderosity',
title: document.querySelector('.title-header').innerHTML.split('<small>')[0].trim(),
productID: document.querySelector('.mainImage').href.replace(/.+?product_(\d+).+/, '$1'),
venderName: []
}
for(let a of document.querySelectorAll('.title-header > small > a')){
if(a.innerText.length > 0){
info.venderName.push(a.innerText);
}
}
}else if(location.host.includes('renderotica')){
info = {
store: 'Renderotica',
title: document.querySelector('.product-info > h1').innerText.trim(),
productID: document.querySelector('.product-info > p > span').innerText.trim(),
venderName: []
}
for(let a of document.querySelectorAll('.product-info > p > a')){
info.venderName.push(a.innerText);
}
// wrap cover with lightbox
const pImg = document.querySelector('.primary-image > img');
const a = document.createElement('a');
a.href = pImg.src;
a.dataset.lightbox = 'image';
pImg.parentNode.append(a);
a.append(pImg);
}
} catch (error) {
console.error(`can't get product info\n`, error);
return;
}
// add switcher for info panel
addBtn('📃', switchInfoPanel);
addBtn('✂', clipImage);
function switchInfoPanel(){
const infoPanel = document.querySelector('#ro-info-panel') || createInfoPanel();
if(infoPanel.style.display === 'block'){
infoPanel.style.display = 'none';
}else{
infoPanel.style.display = 'block';
}
}
function createInfoPanel(){
const infoPanel = document.createElement('div');
infoPanel.id = 'ro-info-panel';
infoPanel.innerHTML = `
<div class="ro-title">
Product Name:
<input type="text" class="value">
<button class="ro-copy">copy</button>
</div>
<div class="ro-vender">
Vender Name:
<input type="text" class="value">
<button class="ro-copy">copy</button>
</div>
<div class="ro-store">
Store Name:
<input type="text" class="value">
<button class="ro-copy">copy</button>
</div>
<div class="ro-id">
Product ID:
<input type="text" class="value">
<button class="ro-copy">copy</button>
</div>
`;
// add style
addStyle(`
#ro-info-panel{
position: fixed;
top: 10rem;
right: 3rem;
z-index: 1;
background-color: #fff6;
padding: 1rem;
border-radius: .5rem;
text-align: right;
}
#ro-info-panel > div{
margin: 5px;
}
.ro-copy{
margin-left: 5px;
cursor: pointer;
}
`);
// fill info panel
infoPanel.querySelector('.ro-title > .value').value = info.title;
infoPanel.querySelector('.ro-vender > .value').value = info.venderName.join(',');
infoPanel.querySelector('.ro-store > .value').value = info.store;
infoPanel.querySelector('.ro-id > .value').value = info.productID;
// bind listener
infoPanel.addEventListener('click', ev=>{
const t = ev.target;
if(t.classList.contains('ro-copy')){
t.previousElementSibling.select();
if(document.execCommand('copy')) console.log('copied.');
}
})
// show node
document.body.append(infoPanel);
return infoPanel;
}
function clipImage(){
const imgBox = document.querySelector('#lightbox');
const img = imgBox.querySelector('img');
if(imgBox.style.display !== 'block'){
alert('please select an image');
return;
}
// get select box
let selectBox = document.querySelector('#ro-select-box');
if(!selectBox){
createSelectBox();
}else if(selectBox.style.display === 'none'){
selectBox.style.display = 'block';
}else{
clip();
selectBox.style.display = 'none';
}
function createSelectBox(){
let selectBox = document.createElement('div');
selectBox.id = 'ro-select-box';
// add style
addStyle(`
#ro-select-box{
position: absolute;
z-index: 99;
cursor: move;
border: 2px dashed #fff;
}
`);
selectBox.style.width = W + 'px';
selectBox.style.height = H + 'px';
selectBox.style.top = '0px';
selectBox.style.left = '0px';
imgBox.querySelector('img').after(selectBox);
selectBox.addEventListener('mousedown', ev=>{
const t = ev.target;
if(t.id !== 'ro-select-box') return;
selectBox.addEventListener('mousemove', handleDragBox);
});
document.body.addEventListener('mouseup', ev=>{
selectBox.removeEventListener('mousemove', handleDragBox);
});
selectBox.addEventListener('contextmenu', ev=>{
ev.preventDefault();
selectBox.style.display = 'none';
});
// create resize corner
const resizeCorner = document.createElement('div');
resizeCorner.id = 'resize-corner';
addStyle(`
#resize-corner{
width: 20px;
height: 20px;
background: red;
position: absolute;
bottom: -5px;
right: -5px;
cursor: se-resize;
border-radius: 10px;
}
`);
resizeCorner.addEventListener('mousedown', ev=>{
document.body.addEventListener('mousemove', handleResize);
});
document.body.addEventListener('mouseup', ev=>{
document.body.removeEventListener('mousemove', handleResize);
});
selectBox.append(resizeCorner);
function handleDragBox(ev){
// console.log('dragging');
const t = ev.target;
const x0 = parseFloat(t.style.left.replace('px', ''));
const y0 = parseFloat(t.style.top.replace('px', ''));
t.style.left = x0 + ev.movementX + 'px';
t.style.top = y0 + ev.movementY + 'px';
}
function handleResize(ev){
// console.log('resizing');
const t = ev.target;
const x = ev.movementX;
const y = x / W * H;
const w0 = parseFloat(selectBox.style.width.replace('px', ''));
const h0 = parseFloat(selectBox.style.height.replace('px', ''));
console.log(x,y,w0,h0);
selectBox.style.width = w0 + x + 'px';
selectBox.style.height = h0 + y + 'px';
}
}
function clip(ev){
// get img
// can't use original img, blocked by CORS
GM_xmlhttpRequest({
url: img.src,
method: 'GET',
responseType: 'blob',
onerror: console.error,
onload: result=>{
createImageBitmap(result.response).then(
bitmap=>{
const ratio = bitmap.height / img.parentElement.clientHeight;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const sx = ratio * parseFloat(selectBox.style.left.replace('px', ''));
const sy = ratio * parseFloat(selectBox.style.top.replace('px', ''));
const sw = ratio * parseFloat(selectBox.style.width.replace('px', ''));
const sh = ratio * parseFloat(selectBox.style.height.replace('px', ''));
canvas.width = W;
canvas.height = H;
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, W, H);
ctx.imageSmoothingQuality = 'high';
// ctx.imageSmoothingEnabled = false;
const a = document.createElement('a');
a.download = info.title + '.jpg';
a.href = canvas.toDataURL('image/jpeg', 0.9);
a.click();
}
);
}
});
}
}
function addStyle(css){
const elm = document.createElement('style');
elm.textContent = css;
document.head.append(elm);
return elm;
}
function addBtn(icon, callback){
let ctn = document.body.querySelector('#my-btn-container');
if(!ctn){
ctn = document.createElement('div');
ctn.id = 'my-btn-container';
addStyle(`
#my-btn-container{
position: fixed;
bottom: 80px;
right: 80px;
z-index: 20000;
}
#my-btn-container > div{
background: #fff8;
border-radius: 10px;
border: 2px solid #0008;
padding: 5px;
margin: 5px 0;
font-size: 20px;
cursor: pointer;
user-select: none;
text-align: center;
}
`);
document.body.append(ctn);
}
const btn = document.createElement('div');
btn.innerText = icon;
btn.addEventListener('click', callback);
ctn.append(btn);
return btn;
}